From 2e4dd12b41bcb0794141586a2876c7c1326136bd Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 12:52:30 +0100 Subject: [PATCH 001/359] feat(social-login): social login with Google is working (#7218) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Víctor Fernández Poyatos --- api/src/backend/api/adapters.py | 4 ++ ui/app/api/auth/callback/github/route.ts | 68 ++++++++++++++++++++++++ ui/app/api/auth/callback/google/route.ts | 68 ++++++++++++++++++++++++ ui/auth.config.ts | 37 ++++++++++++- ui/components/auth/oss/auth-form.tsx | 12 +++-- ui/lib/helper.ts | 35 +++++++++++- ui/types/authFormSchema.ts | 2 + 7 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 ui/app/api/auth/callback/github/route.ts create mode 100644 ui/app/api/auth/callback/google/route.ts diff --git a/api/src/backend/api/adapters.py b/api/src/backend/api/adapters.py index 9a8cb2f044..7ccda0336c 100644 --- a/api/src/backend/api/adapters.py +++ b/api/src/backend/api/adapters.py @@ -30,6 +30,10 @@ class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter): with transaction.atomic(using=MainRouter.admin_db): user = super().save_user(request, sociallogin, form) user.save(using=MainRouter.admin_db) + social_account_name = sociallogin.account.extra_data.get("name") + if social_account_name: + user.name = social_account_name + user.save(using=MainRouter.admin_db) tenant = Tenant.objects.using(MainRouter.admin_db).create( name=f"{user.email.split('@')[0]} default tenant" diff --git a/ui/app/api/auth/callback/github/route.ts b/ui/app/api/auth/callback/github/route.ts new file mode 100644 index 0000000000..8bef55f8a3 --- /dev/null +++ b/ui/app/api/auth/callback/github/route.ts @@ -0,0 +1,68 @@ +"use server"; + +import { NextResponse } from "next/server"; + +import { signIn } from "@/auth.config"; + +export async function GET(req: Request) { + const { searchParams } = new URL(req.url); + + const keyServer = process.env.API_BASE_URL; + + const code = searchParams.get("code"); + + const params = new URLSearchParams(); + params.append("code", code || ""); + + if (!code) { + return NextResponse.json( + { error: "Authorization code is missing" }, + { status: 400 }, + ); + } + + try { + const response = await fetch(`${keyServer}/tokens/github`, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: params.toString(), + }); + + if (!response.ok) { + throw new Error("Failed to exchange code for tokens"); + } + + const data = await response.json(); + const { access, refresh } = data.data.attributes; + + try { + const result = await signIn("social-oauth", { + accessToken: access, + refreshToken: refresh, + redirect: false, + callbackUrl: "/", + }); + + if (result?.error) { + throw new Error(result.error); + } + + return NextResponse.redirect(new URL("/", req.url)); + } catch (error) { + // eslint-disable-next-line no-console + console.error("SignIn error:", error); + return NextResponse.redirect( + new URL("/sign-in?error=AuthenticationFailed", req.url), + ); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error in Github callback:", error); + return NextResponse.json( + { error: (error as Error).message }, + { status: 500 }, + ); + } +} diff --git a/ui/app/api/auth/callback/google/route.ts b/ui/app/api/auth/callback/google/route.ts new file mode 100644 index 0000000000..d52b4eb222 --- /dev/null +++ b/ui/app/api/auth/callback/google/route.ts @@ -0,0 +1,68 @@ +"use server"; + +import { NextResponse } from "next/server"; + +import { signIn } from "@/auth.config"; + +export async function GET(req: Request) { + const { searchParams } = new URL(req.url); + + const keyServer = process.env.API_BASE_URL; + + const code = searchParams.get("code"); + + const params = new URLSearchParams(); + params.append("code", code || ""); + + if (!code) { + return NextResponse.json( + { error: "Authorization code is missing" }, + { status: 400 }, + ); + } + + try { + const response = await fetch(`${keyServer}/tokens/google`, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: params.toString(), + }); + + if (!response.ok) { + throw new Error("Failed to exchange code for tokens"); + } + + const data = await response.json(); + const { access, refresh } = data.data.attributes; + + try { + const result = await signIn("social-oauth", { + accessToken: access, + refreshToken: refresh, + redirect: false, + callbackUrl: "/", + }); + + if (result?.error) { + throw new Error(result.error); + } + + return NextResponse.redirect(new URL("/", req.url)); + } catch (error) { + // eslint-disable-next-line no-console + console.error("SignIn error:", error); + return NextResponse.redirect( + new URL("/sign-in?error=AuthenticationFailed", req.url), + ); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error in Google callback:", error); + return NextResponse.json( + { error: (error as Error).message }, + { status: 500 }, + ); + } +} diff --git a/ui/auth.config.ts b/ui/auth.config.ts index 2d5d223938..6db01ce49a 100644 --- a/ui/auth.config.ts +++ b/ui/auth.config.ts @@ -99,13 +99,48 @@ export const authConfig = { }; }, }), + Credentials({ + id: "social-oauth", + name: "social-oauth", + credentials: { + accessToken: { label: "Access Token", type: "text" }, + refreshToken: { label: "Refresh Token", type: "text" }, + }, + async authorize(credentials) { + const accessToken = credentials?.accessToken; + + if (!accessToken) { + return null; + } + + try { + const userMeResponse = await getUserByMe(accessToken as string); + + const user = { + name: userMeResponse.name, + email: userMeResponse.email, + company: userMeResponse?.company, + dateJoined: userMeResponse.dateJoined, + }; + + return { + ...user, + accessToken: credentials.accessToken, + refreshToken: credentials.refreshToken, + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error in authorize:", error); + return null; + } + }, + }), ], callbacks: { authorized({ auth, request: { nextUrl } }) { const isLoggedIn = !!auth?.user; const isOnDashboard = nextUrl.pathname.startsWith("/"); const isSignUpPage = nextUrl.pathname === "/sign-up"; - //CLOUD API CHANGES // Allow access to sign-up page if (isSignUpPage) return true; diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index 38573accd7..b9c30cc036 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -1,7 +1,8 @@ "use client"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Checkbox, Link } from "@nextui-org/react"; +import { Icon } from "@iconify/react"; +import { Button, Checkbox, Divider, Link } from "@nextui-org/react"; import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -17,6 +18,7 @@ import { FormField, FormMessage, } from "@/components/ui/form"; +import { getAuthUrl } from "@/lib/helper"; import { ApiError, authFormSchema } from "@/types"; export const AuthForm = ({ @@ -285,7 +287,7 @@ export const AuthForm = ({ - {/* {type === "sign-in" && ( + {type === "sign-in" && ( <>
@@ -298,6 +300,8 @@ export const AuthForm = ({ } variant="bordered" + as="a" + href={getAuthUrl("google")} > Continue with Google @@ -310,12 +314,14 @@ export const AuthForm = ({ /> } variant="bordered" + as="a" + href={getAuthUrl("github")} > Continue with Github
- )} */} + )} {type === "sign-in" ? (

Need to create an account?  diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index 66a0e413f9..e985390c7a 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -1,5 +1,38 @@ import { getTask } from "@/actions/task"; -import { MetaDataProps, PermissionInfo } from "@/types"; +import { AuthSocialProvider, MetaDataProps, PermissionInfo } from "@/types"; + +export const getAuthUrl = (provider: AuthSocialProvider) => { + const config = { + google: { + baseUrl: "https://accounts.google.com/o/oauth2/v2/auth", + params: { + redirect_uri: process.env.NEXT_PUBLIC_GOOGLE_CALLBACK_URI, + prompt: "consent", + response_type: "code", + client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, + scope: "openid email profile", + access_type: "offline", + }, + }, + github: { + baseUrl: "https://github.com/login/oauth/authorize", + params: { + client_id: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_ID, + redirect_uri: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CALLBACK_URL, + scope: "user:email", + }, + }, + }; + + const { baseUrl, params } = config[provider]; + const url = new URL(baseUrl); + + Object.entries(params).forEach(([key, value]) => { + url.searchParams.set(key, value || ""); + }); + + return url.toString(); +}; export async function checkTaskStatus( taskId: string, diff --git a/ui/types/authFormSchema.ts b/ui/types/authFormSchema.ts index 58737a1f8a..e08c14ea53 100644 --- a/ui/types/authFormSchema.ts +++ b/ui/types/authFormSchema.ts @@ -1,5 +1,7 @@ import { z } from "zod"; +export type AuthSocialProvider = "google" | "github"; + export const authFormSchema = (type: string) => z .object({ From 07419fd5e197af5a47f2180fd0f47c09941fad9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?= Date: Thu, 13 Mar 2025 13:37:17 +0100 Subject: [PATCH 002/359] fix(exports): change the way to remove the local export files after s3 upload (#7172) --- api/CHANGELOG.md | 7 +++++++ api/poetry.lock | 3 +++ api/pyproject.toml | 2 +- api/src/backend/tasks/tasks.py | 9 +++++++-- poetry.lock | 2 ++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 256512d561..47b25c5e33 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -12,6 +12,13 @@ All notable changes to the **Prowler API** are documented in this file. --- +## [v1.5.1] (Prowler v5.4.1) + +### Fixed +- Fixed a race condition when deleting export files after the S3 upload [(#7172)](https://github.com/prowler-cloud/prowler/pull/7172). + +--- + ## [v1.5.0] (Prowler v5.4.0) ### Added diff --git a/api/poetry.lock b/api/poetry.lock index 8e5d3173d9..02bc2aaef4 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -3700,6 +3700,7 @@ files = [ {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, @@ -3708,6 +3709,8 @@ files = [ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, diff --git a/api/pyproject.toml b/api/pyproject.toml index fa9c14148a..c5e151aab6 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -34,7 +34,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.5.0" +version = "1.6.0" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/tasks/tasks.py b/api/src/backend/tasks/tasks.py index 607f3cacdd..05c1919f17 100644 --- a/api/src/backend/tasks/tasks.py +++ b/api/src/backend/tasks/tasks.py @@ -1,3 +1,4 @@ +from pathlib import Path from shutil import rmtree from celery import chain, shared_task @@ -264,10 +265,14 @@ def generate_outputs(scan_id: str, provider_id: str, tenant_id: str): uploaded = _upload_to_s3(tenant_id, output_directory, scan_id) if uploaded: + # Remove the local files after upload + try: + rmtree(Path(output_directory).parent, ignore_errors=True) + except FileNotFoundError as e: + logger.error(f"Error deleting output files: {e}") + output_directory = uploaded uploaded = True - # Remove the local files after upload - rmtree(DJANGO_TMP_OUTPUT_DIRECTORY, ignore_errors=True) else: uploaded = False diff --git a/poetry.lock b/poetry.lock index 7a4e9e4155..628d7efb46 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2160,6 +2160,8 @@ python-versions = "*" groups = ["dev"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] From 56445c97533dd458cc234e59d41c220b8cfa6125 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 13:39:26 +0100 Subject: [PATCH 003/359] chore: update changelog (#7223) --- ui/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index a133a45f24..dcd310a8d4 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler UI** are documented in this file. #### 🚀 Added +- Social login integration with Google and GitHub [(#7218)](https://github.com/prowler-cloud/prowler/pull/7218) - Added `one-time scan` feature: Adds support for single scan execution. [(#7188)](https://github.com/prowler-cloud/prowler/pull/7188) - Accepted invitations can no longer be edited. [(#7198)](https://github.com/prowler-cloud/prowler/pull/7198) From 9594c4c99fdf1842e7193f5e83c98011a239dddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?= Date: Thu, 13 Mar 2025 13:47:00 +0100 Subject: [PATCH 004/359] fix: add a handled response in case local files are missing (#7183) --- api/CHANGELOG.md | 1 + api/src/backend/api/tests/test_views.py | 19 +++++++++++++++++++ api/src/backend/api/v1/views.py | 10 +++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 47b25c5e33..183f82d495 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to the **Prowler API** are documented in this file. ## [v1.5.1] (Prowler v5.4.1) ### Fixed +- Added a handled response in case local files are missing [(#7183)](https://github.com/prowler-cloud/prowler/pull/7183). - Fixed a race condition when deleting export files after the S3 upload [(#7172)](https://github.com/prowler-cloud/prowler/pull/7172). --- diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 597561b310..013a22bd12 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -2288,6 +2288,25 @@ class TestScanViewSet: assert f'filename="{expected_filename}"' in content_disposition assert response.content == b"s3 zip content" + def test_report_s3_success_no_local_files( + self, authenticated_client, scans_fixture, monkeypatch + ): + """ + When output_location is a local path and glob.glob returns an empty list, + the view should return HTTP 404 with detail "The scan has no reports." + """ + scan = scans_fixture[0] + scan.output_location = "/tmp/nonexistent_report_pattern.zip" + scan.state = StateChoices.COMPLETED + scan.save() + monkeypatch.setattr("api.v1.views.glob.glob", lambda pattern: []) + + url = reverse("scan-report", kwargs={"pk": scan.id}) + response = authenticated_client.get(url) + + assert response.status_code == 404 + assert response.json()["errors"]["detail"] == "The scan has no reports." + def test_report_local_file( self, authenticated_client, scans_fixture, tmp_path, monkeypatch ): diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 993b3dfbed..7801e93110 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -1,6 +1,7 @@ import glob import os +import sentry_sdk from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter from botocore.exceptions import ClientError, NoCredentialsError, ParamValidationError @@ -1290,7 +1291,14 @@ class ScanViewSet(BaseRLSViewSet): filename = os.path.basename(output_location.split("/")[-1]) else: zip_files = glob.glob(output_location) - file_path = zip_files[0] + try: + file_path = zip_files[0] + except IndexError as e: + sentry_sdk.capture_exception(e) + return Response( + {"detail": "The scan has no reports."}, + status=status.HTTP_404_NOT_FOUND, + ) with open(file_path, "rb") as f: file_content = f.read() filename = os.path.basename(file_path) From 7514484c42067a64487590aecf766c932d99e970 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 13:48:01 +0100 Subject: [PATCH 005/359] chore: change wording for launching a single scan (#7226) --- ui/components/providers/workflow/forms/test-connection-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/providers/workflow/forms/test-connection-form.tsx b/ui/components/providers/workflow/forms/test-connection-form.tsx index 57dfb2cf42..84bd803f06 100644 --- a/ui/components/providers/workflow/forms/test-connection-form.tsx +++ b/ui/components/providers/workflow/forms/test-connection-form.tsx @@ -280,7 +280,7 @@ export const TestConnectionForm = ({ wrapper: "checkbox-update", }} > - Run a one-time scan (disable daily schedule). + Run a single scan (no recurring schedule). )} From 44c70b5d011b27508bcc7b65fcf9eba5dd9d09c2 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 13:57:16 +0100 Subject: [PATCH 006/359] chore: remove unused regions (#7229) --- .../filters/custom-region-selection.tsx | 8 +- ui/lib/helper.ts | 94 ------------------- 2 files changed, 2 insertions(+), 100 deletions(-) diff --git a/ui/components/filters/custom-region-selection.tsx b/ui/components/filters/custom-region-selection.tsx index adab82823b..6cc4d78c18 100644 --- a/ui/components/filters/custom-region-selection.tsx +++ b/ui/components/filters/custom-region-selection.tsx @@ -4,12 +4,10 @@ import { Select, SelectItem } from "@nextui-org/react"; import { useRouter, useSearchParams } from "next/navigation"; import React, { useCallback, useMemo } from "react"; -import { regions } from "@/lib/helper"; - export const CustomRegionSelection: React.FC = () => { const router = useRouter(); const searchParams = useSearchParams(); - + const region = "none"; // Memoize selected keys based on the URL const selectedKeys = useMemo(() => { const params = searchParams.get("filter[regions]"); @@ -44,9 +42,7 @@ export const CustomRegionSelection: React.FC = () => { applyRegionFilter(Array.from(keys) as string[]) } > - {regions.map((region) => ( - {region.label} - ))} + {region} ); }; diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index e985390c7a..cf5bd39003 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -123,100 +123,6 @@ export const getErrorMessage = async (error: unknown): Promise => { return message; }; -export const regions = [ - // AWS Regions (ordered by usage) - { key: "us-east-1", label: "AWS - US East 1" }, - { key: "us-west-1", label: "AWS - US West 1" }, - { key: "us-west-2", label: "AWS - US West 2" }, - { key: "eu-west-1", label: "AWS - EU West 1" }, - { key: "eu-central-1", label: "AWS - EU Central 1" }, - { key: "ap-southeast-1", label: "AWS - AP Southeast 1" }, - { key: "ap-northeast-1", label: "AWS - AP Northeast 1" }, - { key: "ap-southeast-2", label: "AWS - AP Southeast 2" }, - { key: "ca-central-1", label: "AWS - CA Central 1" }, - { key: "sa-east-1", label: "AWS - SA East 1" }, - { key: "af-south-1", label: "AWS - AF South 1" }, - { key: "ap-east-1", label: "AWS - AP East 1" }, - { key: "ap-northeast-2", label: "AWS - AP Northeast 2" }, - { key: "ap-northeast-3", label: "AWS - AP Northeast 3" }, - { key: "ap-south-1", label: "AWS - AP South 1" }, - { key: "ap-south-2", label: "AWS - AP South 2" }, - { key: "ap-southeast-3", label: "AWS - AP Southeast 3" }, - { key: "ap-southeast-4", label: "AWS - AP Southeast 4" }, - { key: "ca-west-1", label: "AWS - CA West 1" }, - { key: "eu-central-2", label: "AWS - EU Central 2" }, - { key: "eu-north-1", label: "AWS - EU North 1" }, - { key: "eu-south-1", label: "AWS - EU South 1" }, - { key: "eu-south-2", label: "AWS - EU South 2" }, - { key: "eu-west-2", label: "AWS - EU West 2" }, - { key: "eu-west-3", label: "AWS - EU West 3" }, - { key: "il-central-1", label: "AWS - IL Central 1" }, - { key: "me-central-1", label: "AWS - ME Central 1" }, - { key: "me-south-1", label: "AWS - ME South 1" }, - - // Azure Regions (ordered by usage) - { key: "eastus", label: "Azure - East US" }, - { key: "eastus2", label: "Azure - East US 2" }, - { key: "westeurope", label: "Azure - West Europe" }, - { key: "southeastasia", label: "Azure - Southeast Asia" }, - { key: "uksouth", label: "Azure - UK South" }, - { key: "northeurope", label: "Azure - North Europe" }, - { key: "centralus", label: "Azure - Central US" }, - { key: "westus2", label: "Azure - West US 2" }, - { key: "southcentralus", label: "Azure - South Central US" }, - { key: "australiaeast", label: "Azure - Australia East" }, - { key: "canadacentral", label: "Azure - Canada Central" }, - { key: "japaneast", label: "Azure - Japan East" }, - { key: "koreacentral", label: "Azure - Korea Central" }, - { key: "southafricanorth", label: "Azure - South Africa North" }, - { key: "brazilsouth", label: "Azure - Brazil South" }, - { key: "francecentral", label: "Azure - France Central" }, - { key: "germanywestcentral", label: "Azure - Germany West Central" }, - { key: "switzerlandnorth", label: "Azure - Switzerland North" }, - { key: "uaenorth", label: "Azure - UAE North" }, - // Remaining Azure Regions (less frequently used) - { key: "westus", label: "Azure - West US" }, - { key: "northcentralus", label: "Azure - North Central US" }, - { key: "australiasoutheast", label: "Azure - Australia Southeast" }, - { key: "southindia", label: "Azure - South India" }, - { key: "westindia", label: "Azure - West India" }, - { key: "canadaeast", label: "Azure - Canada East" }, - { key: "francesouth", label: "Azure - France South" }, - { key: "norwayeast", label: "Azure - Norway East" }, - { key: "switzerlandwest", label: "Azure - Switzerland West" }, - { key: "ukwest", label: "Azure - UK West" }, - { key: "uaecentral", label: "Azure - UAE Central" }, - { key: "brazilsoutheast", label: "Azure - Brazil Southeast" }, - - // GCP Regions (ordered by usage) - { key: "us-central1", label: "GCP - US Central (Iowa)" }, - { key: "us-east1", label: "GCP - US East (South Carolina)" }, - { key: "us-west1", label: "GCP - US West (Oregon)" }, - { key: "europe-west1", label: "GCP - Europe West (Belgium)" }, - { key: "asia-east1", label: "GCP - Asia East (Taiwan)" }, - { key: "asia-northeast1", label: "GCP - Asia Northeast (Tokyo)" }, - { key: "europe-west2", label: "GCP - Europe West (London)" }, - { key: "europe-west3", label: "GCP - Europe West (Frankfurt)" }, - { key: "europe-west4", label: "GCP - Europe West (Netherlands)" }, - { key: "asia-southeast1", label: "GCP - Asia Southeast (Singapore)" }, - { key: "australia-southeast1", label: "GCP - Australia Southeast (Sydney)" }, - { - key: "northamerica-northeast1", - label: "GCP - North America Northeast (Montreal)", - }, - // Remaining GCP Regions - { key: "asia-east2", label: "GCP - Asia East (Hong Kong)" }, - { key: "asia-northeast2", label: "GCP - Asia Northeast (Osaka)" }, - { key: "asia-northeast3", label: "GCP - Asia Northeast (Seoul)" }, - { key: "asia-south1", label: "GCP - Asia South (Mumbai)" }, - { key: "asia-southeast2", label: "GCP - Asia Southeast (Jakarta)" }, - { key: "europe-north1", label: "GCP - Europe North (Finland)" }, - { key: "europe-west6", label: "GCP - Europe West (Zurich)" }, - { key: "southamerica-east1", label: "GCP - South America East (São Paulo)" }, - { key: "us-west2", label: "GCP - US West (Los Angeles)" }, - { key: "us-east4", label: "GCP - US East (Northern Virginia)" }, -]; - export const permissionFormFields: PermissionInfo[] = [ { field: "manage_users", From 2b7b887b87509ea9a318a728c800a1946262e57d Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 14:20:09 +0100 Subject: [PATCH 007/359] chore: social auth is algo in sign-up page (#7231) --- ui/components/auth/oss/auth-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index b9c30cc036..0c82cb3d13 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -287,7 +287,7 @@ export const AuthForm = ({ - {type === "sign-in" && ( + {!invitationToken && ( <>

From f2e19d377a11181ece737a90cab2c958496c9187 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 13 Mar 2025 17:07:17 +0100 Subject: [PATCH 008/359] chore(social-login): rename env.vars for social login (#7232) --- api/src/backend/config/settings/social_login.py | 14 +++++++------- ui/lib/helper.ts | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/api/src/backend/config/settings/social_login.py b/api/src/backend/config/settings/social_login.py index 035a166279..6a48a0c38f 100644 --- a/api/src/backend/config/settings/social_login.py +++ b/api/src/backend/config/settings/social_login.py @@ -1,13 +1,13 @@ from config.env import env -# Google Oauth settings -GOOGLE_OAUTH_CLIENT_ID = env("DJANGO_GOOGLE_OAUTH_CLIENT_ID", default="") -GOOGLE_OAUTH_CLIENT_SECRET = env("DJANGO_GOOGLE_OAUTH_CLIENT_SECRET", default="") -GOOGLE_OAUTH_CALLBACK_URL = env("DJANGO_GOOGLE_OAUTH_CALLBACK_URL", default="") +# Provider Oauth settings +GOOGLE_OAUTH_CLIENT_ID = env("SOCIAL_GOOGLE_OAUTH_CLIENT_ID", default="") +GOOGLE_OAUTH_CLIENT_SECRET = env("SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET", default="") +GOOGLE_OAUTH_CALLBACK_URL = env("SOCIAL_GOOGLE_OAUTH_CALLBACK_URL", default="") -GITHUB_OAUTH_CLIENT_ID = env("DJANGO_GITHUB_OAUTH_CLIENT_ID", default="") -GITHUB_OAUTH_CLIENT_SECRET = env("DJANGO_GITHUB_OAUTH_CLIENT_SECRET", default="") -GITHUB_OAUTH_CALLBACK_URL = env("DJANGO_GITHUB_OAUTH_CALLBACK_URL", default="") +GITHUB_OAUTH_CLIENT_ID = env("SOCIAL_GITHUB_OAUTH_CLIENT_ID", default="") +GITHUB_OAUTH_CLIENT_SECRET = env("SOCIAL_GITHUB_OAUTH_CLIENT_SECRET", default="") +GITHUB_OAUTH_CALLBACK_URL = env("SOCIAL_GITHUB_OAUTH_CALLBACK_URL", default="") # Allauth settings ACCOUNT_LOGIN_METHODS = {"email"} # Use Email / Password authentication diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index cf5bd39003..d1dee56161 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -6,10 +6,10 @@ export const getAuthUrl = (provider: AuthSocialProvider) => { google: { baseUrl: "https://accounts.google.com/o/oauth2/v2/auth", params: { - redirect_uri: process.env.NEXT_PUBLIC_GOOGLE_CALLBACK_URI, + redirect_uri: process.env.SOCIAL_GOOGLE_OAUTH_CALLBACK_URL, prompt: "consent", response_type: "code", - client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, + client_id: process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_ID, scope: "openid email profile", access_type: "offline", }, @@ -17,8 +17,8 @@ export const getAuthUrl = (provider: AuthSocialProvider) => { github: { baseUrl: "https://github.com/login/oauth/authorize", params: { - client_id: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_ID, - redirect_uri: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CALLBACK_URL, + client_id: process.env.SOCIAL_GITHUB_OAUTH_CLIENT_ID, + redirect_uri: process.env.SOCIAL_GITHUB_OAUTH_CALLBACK_URL, scope: "user:email", }, }, From 89d4c521ba52ce577f04670284e175f8351a46f5 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 14 Mar 2025 11:32:22 +0100 Subject: [PATCH 009/359] chore(social-login): disable social login buttons when env vars are not set (#7238) --- ui/app/(auth)/sign-in/page.tsx | 9 ++++++++- ui/app/(auth)/sign-up/page.tsx | 11 ++++++++++- ui/components/auth/oss/auth-form.tsx | 7 +++++++ ui/lib/helper.ts | 8 ++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ui/app/(auth)/sign-in/page.tsx b/ui/app/(auth)/sign-in/page.tsx index b5bd978029..cb8b2df43b 100644 --- a/ui/app/(auth)/sign-in/page.tsx +++ b/ui/app/(auth)/sign-in/page.tsx @@ -1,7 +1,14 @@ import { AuthForm } from "@/components/auth/oss"; +import { isGithubOAuthEnabled, isGoogleOAuthEnabled } from "@/lib/helper"; const SignIn = () => { - return ; + return ( + + ); }; export default SignIn; diff --git a/ui/app/(auth)/sign-up/page.tsx b/ui/app/(auth)/sign-up/page.tsx index 28149bb200..37f1bc92f7 100644 --- a/ui/app/(auth)/sign-up/page.tsx +++ b/ui/app/(auth)/sign-up/page.tsx @@ -1,4 +1,6 @@ import { AuthForm } from "@/components/auth/oss"; +import { isGithubOAuthEnabled } from "@/lib/helper"; +import { isGoogleOAuthEnabled } from "@/lib/helper"; import { SearchParamsProps } from "@/types"; const SignUp = ({ searchParams }: { searchParams: SearchParamsProps }) => { @@ -7,7 +9,14 @@ const SignUp = ({ searchParams }: { searchParams: SearchParamsProps }) => { ? searchParams.invitation_token : null; - return ; + return ( + + ); }; export default SignUp; diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index 0c82cb3d13..90c86fe94a 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -25,10 +25,14 @@ export const AuthForm = ({ type, invitationToken, isCloudEnv, + isGoogleOAuthEnabled, + isGithubOAuthEnabled, }: { type: string; invitationToken?: string | null; isCloudEnv?: boolean; + isGoogleOAuthEnabled?: boolean; + isGithubOAuthEnabled?: boolean; }) => { const formSchema = authFormSchema(type); const router = useRouter(); @@ -302,9 +306,11 @@ export const AuthForm = ({ variant="bordered" as="a" href={getAuthUrl("google")} + isDisabled={!isGoogleOAuthEnabled} > Continue with Google + diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index d1dee56161..b7e67f03c9 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -34,6 +34,14 @@ export const getAuthUrl = (provider: AuthSocialProvider) => { return url.toString(); }; +export const isGoogleOAuthEnabled = + process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_ID !== "" && + process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET !== ""; + +export const isGithubOAuthEnabled = + process.env.SOCIAL_GITHUB_OAUTH_CLIENT_ID !== "" && + process.env.SOCIAL_GITHUB_OAUTH_CLIENT_SECRET !== ""; + export async function checkTaskStatus( taskId: string, ): Promise<{ completed: boolean; error?: string }> { From 1ab2a80eabd3d2e6d2446fbb923faf8644c407bc Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Sat, 15 Mar 2025 12:12:30 +0100 Subject: [PATCH 010/359] chore: improve UX when social login is not enabled (#7242) --- ui/components/auth/oss/auth-form.tsx | 93 +++++++++++++++++++++------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index 90c86fe94a..2ab7cefbd2 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -2,7 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { Icon } from "@iconify/react"; -import { Button, Checkbox, Divider, Link } from "@nextui-org/react"; +import { Button, Checkbox, Divider, Link, Tooltip } from "@nextui-org/react"; import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -299,33 +299,78 @@ export const AuthForm = ({
-
} - variant="bordered" - as="a" - href={getAuthUrl("google")} - isDisabled={!isGoogleOAuthEnabled} + placement="right-start" + shadow="sm" + isDisabled={isGoogleOAuthEnabled} + className="w-96" > - Continue with Google - - - + + + + Github Sign-in is not enabled. Configure the social OAuth + environment variables to enable it. + + Read the docs + + } - variant="bordered" - as="a" - href={getAuthUrl("github")} - isDisabled={!isGithubOAuthEnabled} + placement="right-start" + shadow="sm" + isDisabled={isGithubOAuthEnabled} + className="w-96" > - Continue with Github - + + + + )} From 64d866271ccfad994b794c97b0d39d7aef0abaf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 17 Mar 2025 07:33:00 +0100 Subject: [PATCH 011/359] fix(scan): add compliance info inside finding (#5649) --- prowler/lib/scan/scan.py | 45 ++++++++++++++++++++++-------- prowler/providers/common/models.py | 32 ++++++++++----------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/prowler/lib/scan/scan.py b/prowler/lib/scan/scan.py index b5b621f28e..00d063725d 100644 --- a/prowler/lib/scan/scan.py +++ b/prowler/lib/scan/scan.py @@ -1,4 +1,5 @@ import datetime +from types import SimpleNamespace from typing import Generator from prowler.lib.check.check import ( @@ -22,7 +23,7 @@ from prowler.lib.scan.exceptions.exceptions import ( ScanInvalidSeverityError, ScanInvalidStatusError, ) -from prowler.providers.common.models import Audit_Metadata +from prowler.providers.common.models import Audit_Metadata, ProviderOutputOptions from prowler.providers.common.provider import Provider @@ -38,6 +39,8 @@ class Scan: _progress: float = 0.0 _duration: int = 0 _status: list[str] = None + _bulk_checks_metadata: dict[str, CheckMetadata] + _bulk_compliance_frameworks: dict def __init__( self, @@ -88,18 +91,18 @@ class Scan: raise ScanInvalidStatusError(f"Invalid status provided: {s}.") # Load bulk compliance frameworks - bulk_compliance_frameworks = Compliance.get_bulk(provider.type) + self._bulk_compliance_frameworks = Compliance.get_bulk(provider.type) # Get bulk checks metadata for the provider - bulk_checks_metadata = CheckMetadata.get_bulk(provider.type) + self._bulk_checks_metadata = CheckMetadata.get_bulk(provider.type) # Complete checks metadata with the compliance framework specification - bulk_checks_metadata = update_checks_metadata_with_compliance( - bulk_compliance_frameworks, bulk_checks_metadata + self._bulk_checks_metadata = update_checks_metadata_with_compliance( + self._bulk_compliance_frameworks, self._bulk_checks_metadata ) # Create a list of valid categories valid_categories = set() - for check, metadata in bulk_checks_metadata.items(): + for check, metadata in self._bulk_checks_metadata.items(): for category in metadata.Categories: if category not in valid_categories: valid_categories.add(category) @@ -107,7 +110,7 @@ class Scan: # Validate checks if checks: for check in checks: - if check not in bulk_checks_metadata.keys(): + if check not in self._bulk_checks_metadata.keys(): raise ScanInvalidCheckError(f"Invalid check provided: {check}.") # Validate services @@ -121,7 +124,7 @@ class Scan: # Validate compliances if compliances: for compliance in compliances: - if compliance not in bulk_compliance_frameworks.keys(): + if compliance not in self._bulk_compliance_frameworks.keys(): raise ScanInvalidComplianceFrameworkError( f"Invalid compliance provided: {compliance}." ) @@ -147,8 +150,8 @@ class Scan: # Load checks to execute self._checks_to_execute = sorted( load_checks_to_execute( - bulk_checks_metadata=bulk_checks_metadata, - bulk_compliance_frameworks=bulk_compliance_frameworks, + bulk_checks_metadata=self._bulk_checks_metadata, + bulk_compliance_frameworks=self._bulk_compliance_frameworks, check_list=checks, service_list=services, compliance_frameworks=compliances, @@ -215,9 +218,17 @@ class Scan: def duration(self) -> int: return self._duration + @property + def bulk_checks_metadata(self) -> dict[str, CheckMetadata]: + return self._bulk_checks_metadata + + @property + def bulk_compliance_frameworks(self) -> dict[str, CheckMetadata]: + return self._bulk_compliance_frameworks + def scan( self, - custom_checks_metadata: dict = {}, + custom_checks_metadata: dict = None, ) -> Generator[tuple[float, list[Finding]], None, None]: """ Executes the scan by iterating over the checks to execute and executing each check. @@ -234,6 +245,14 @@ class Scan: Exception: If any other error occurs during the execution of a check. """ try: + # Using SimpleNamespace to create a mocked object + arguments = SimpleNamespace() + + output_options = ProviderOutputOptions( + arguments=arguments, + bulk_checks_metadata=self.bulk_checks_metadata, + ) + checks_to_execute = self.checks_to_execute # Initialize the Audit Metadata # TODO: this should be done in the provider class @@ -301,7 +320,9 @@ class Scan: try: findings.append( Finding.generate_output( - self._provider, finding, output_options=None + self.provider, + finding, + output_options=output_options, ) ) except Exception: diff --git a/prowler/providers/common/models.py b/prowler/providers/common/models.py index ebe2ae16fb..47c9ebd2fe 100644 --- a/prowler/providers/common/models.py +++ b/prowler/providers/common/models.py @@ -28,34 +28,34 @@ class ProviderOutputOptions: unix_timestamp: bool def __init__(self, arguments, bulk_checks_metadata): - self.status = arguments.status - self.output_modes = arguments.output_formats - self.output_directory = arguments.output_directory - self.verbose = arguments.verbose + self.status = getattr(arguments, "status", None) + self.output_modes = getattr(arguments, "output_formats", None) + self.output_directory = getattr(arguments, "output_directory", None) + self.verbose = getattr(arguments, "verbose", None) self.bulk_checks_metadata = bulk_checks_metadata - self.only_logs = arguments.only_logs - self.unix_timestamp = arguments.unix_timestamp - self.shodan_api_key = arguments.shodan + self.only_logs = getattr(arguments, "only_logs", None) + self.unix_timestamp = getattr(arguments, "unix_timestamp", None) + self.shodan_api_key = getattr(arguments, "shodan", None) self.fixer = getattr(arguments, "fixer", None) # Shodan API Key - if arguments.shodan: + if self.shodan_api_key: # TODO: revisit this logic provider = Provider.get_global_provider() updated_audit_config = Provider.update_provider_config( - provider.audit_config, "shodan_api_key", arguments.shodan + provider.audit_config, "shodan_api_key", self.shodan_api_key ) if updated_audit_config: provider._audit_config = updated_audit_config # Check output directory, if it is not created -> create it - if arguments.output_directory and not self.fixer: - if not isdir(arguments.output_directory): - if arguments.output_formats: - makedirs(arguments.output_directory, exist_ok=True) - if not isdir(arguments.output_directory + "/compliance"): - if arguments.output_formats: - makedirs(arguments.output_directory + "/compliance", exist_ok=True) + if self.output_directory and not self.fixer: + if not isdir(self.output_directory): + if self.output_modes: + makedirs(self.output_directory, exist_ok=True) + if not isdir(self.output_directory + "/compliance"): + if self.output_modes: + makedirs(self.output_directory + "/compliance", exist_ok=True) @dataclass From 3a55c2ee07f51c7eea0529daeef118dcbeb4651b Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 17 Mar 2025 07:49:44 +0100 Subject: [PATCH 012/359] chore(regions_update): Changes in regions for AWS services (#7245) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> --- .../providers/aws/aws_regions_by_service.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index ba6e72a832..f020c6f038 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -431,6 +431,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", "ca-central-1", "ca-west-1", "eu-central-1", @@ -1323,6 +1324,8 @@ "eu-central-1", "eu-central-2", "eu-north-1", + "eu-south-1", + "eu-south-2", "eu-west-1", "eu-west-2", "eu-west-3", @@ -1352,6 +1355,8 @@ "eu-central-1", "eu-central-2", "eu-north-1", + "eu-south-1", + "eu-south-2", "eu-west-1", "eu-west-2", "eu-west-3", @@ -1391,6 +1396,8 @@ "eu-central-1", "eu-central-2", "eu-north-1", + "eu-south-1", + "eu-south-2", "eu-west-1", "eu-west-2", "eu-west-3", @@ -2325,6 +2332,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", "ca-central-1", "eu-central-1", "eu-central-2", @@ -6390,6 +6398,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -7172,7 +7181,9 @@ "us-west-1", "us-west-2" ], - "aws-cn": [], + "aws-cn": [ + "cn-northwest-1" + ], "aws-us-gov": [ "us-gov-east-1", "us-gov-west-1" @@ -7528,6 +7539,7 @@ "ap-southeast-1", "ap-southeast-2", "ap-southeast-3", + "ap-southeast-5", "ca-central-1", "eu-central-1", "eu-north-1", @@ -7991,6 +8003,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", "ca-central-1", "ca-west-1", "eu-central-1", @@ -10709,6 +10722,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", From 489b5abf82836838674c650de2826211e3b14ac6 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 17 Mar 2025 09:02:56 +0100 Subject: [PATCH 013/359] chore(regions_update): Changes in regions for AWS services (#7237) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> From db7ffea24db0973533915b8d35b4d8e3f998daeb Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 17 Mar 2025 10:23:01 +0100 Subject: [PATCH 014/359] chore: add env var for social login (#7251) --- .env | 2 +- ui/app/api/auth/callback/github/route.ts | 5 +++-- ui/app/api/auth/callback/google/route.ts | 5 +++-- ui/lib/helper.ts | 2 ++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 9403b39152..ef04a95338 100644 --- a/.env +++ b/.env @@ -4,7 +4,7 @@ #### Prowler UI Configuration #### PROWLER_UI_VERSION="stable" -SITE_URL=http://localhost:3000 +AUTH_URL=http://localhost:3000 API_BASE_URL=http://prowler-api:8080/api/v1 NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs AUTH_TRUST_HOST=true diff --git a/ui/app/api/auth/callback/github/route.ts b/ui/app/api/auth/callback/github/route.ts index 8bef55f8a3..918d019360 100644 --- a/ui/app/api/auth/callback/github/route.ts +++ b/ui/app/api/auth/callback/github/route.ts @@ -3,6 +3,7 @@ import { NextResponse } from "next/server"; import { signIn } from "@/auth.config"; +import { baseUrl } from "@/lib/helper"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); @@ -42,14 +43,14 @@ export async function GET(req: Request) { accessToken: access, refreshToken: refresh, redirect: false, - callbackUrl: "/", + callbackUrl: `${baseUrl}/`, }); if (result?.error) { throw new Error(result.error); } - return NextResponse.redirect(new URL("/", req.url)); + return NextResponse.redirect(new URL("/", baseUrl)); } catch (error) { // eslint-disable-next-line no-console console.error("SignIn error:", error); diff --git a/ui/app/api/auth/callback/google/route.ts b/ui/app/api/auth/callback/google/route.ts index d52b4eb222..521ed1c413 100644 --- a/ui/app/api/auth/callback/google/route.ts +++ b/ui/app/api/auth/callback/google/route.ts @@ -3,6 +3,7 @@ import { NextResponse } from "next/server"; import { signIn } from "@/auth.config"; +import { baseUrl } from "@/lib/helper"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); @@ -42,14 +43,14 @@ export async function GET(req: Request) { accessToken: access, refreshToken: refresh, redirect: false, - callbackUrl: "/", + callbackUrl: `${baseUrl}/`, }); if (result?.error) { throw new Error(result.error); } - return NextResponse.redirect(new URL("/", req.url)); + return NextResponse.redirect(new URL("/", baseUrl)); } catch (error) { // eslint-disable-next-line no-console console.error("SignIn error:", error); diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index b7e67f03c9..428270ed2e 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -1,6 +1,8 @@ import { getTask } from "@/actions/task"; import { AuthSocialProvider, MetaDataProps, PermissionInfo } from "@/types"; +export const baseUrl = process.env.AUTH_URL || "http://localhost:3000"; + export const getAuthUrl = (provider: AuthSocialProvider) => { const config = { google: { From c4f6161c73ac0afd057c61f1f5d6bf66a29845f0 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 17 Mar 2025 17:11:28 +0545 Subject: [PATCH 015/359] chore(security): Pin actions to the Full-Length Commit SHA (#7249) --- .../workflows/api-build-lint-push-containers.yml | 12 ++++++------ .github/workflows/api-codeql.yml | 6 +++--- .github/workflows/api-pull-request.yml | 14 +++++++------- .github/workflows/backport.yml | 4 ++-- .github/workflows/build-documentation-on-pr.yml | 2 +- .github/workflows/conventional-commit.yml | 2 +- .github/workflows/find-secrets.yml | 4 ++-- .github/workflows/labeler.yml | 2 +- .../workflows/sdk-build-lint-push-containers.yml | 14 +++++++------- .github/workflows/sdk-codeql.yml | 6 +++--- .github/workflows/sdk-pull-request.yml | 8 ++++---- .github/workflows/sdk-pypi-release.yml | 4 ++-- .../workflows/sdk-refresh-aws-services-regions.yml | 8 ++++---- .../workflows/ui-build-lint-push-containers.yml | 12 ++++++------ .github/workflows/ui-codeql.yml | 6 +++--- .github/workflows/ui-pull-request.yml | 10 +++++----- 16 files changed, 57 insertions(+), 57 deletions(-) diff --git a/.github/workflows/api-build-lint-push-containers.yml b/.github/workflows/api-build-lint-push-containers.yml index 049a06866f..4a24e47031 100644 --- a/.github/workflows/api-build-lint-push-containers.yml +++ b/.github/workflows/api-build-lint-push-containers.yml @@ -61,7 +61,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set short git commit SHA id: vars @@ -70,18 +70,18 @@ jobs: echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build and push container image (latest) # Comment the following line for testing if: github.event_name == 'push' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.WORKING_DIRECTORY }} # Set push: false for testing @@ -94,7 +94,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.WORKING_DIRECTORY }} push: true @@ -106,7 +106,7 @@ jobs: - name: Trigger deployment if: github.event_name == 'push' - uses: peter-evans/repository-dispatch@v3 + uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} repository: ${{ secrets.CLOUD_DISPATCH }} diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml index b9b1b966ca..5a1a12ea13 100644 --- a/.github/workflows/api-codeql.yml +++ b/.github/workflows/api-codeql.yml @@ -44,16 +44,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/api-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index bbeddb1114..312bcd68a3 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -71,11 +71,11 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@v45 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 with: files: api/** files_ignore: | @@ -94,7 +94,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" @@ -167,7 +167,7 @@ jobs: - name: Upload coverage reports to Codecov if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -175,11 +175,11 @@ jobs: test-container-build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build Container - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.API_WORKING_DIR }} push: false diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index d74b96f3f8..e825a8de49 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Check labels id: preview_label_check - uses: docker://agilepathway/pull-request-label-checker:v1.6.55 + uses: docker://agilepathway/pull-request-label-checker:sha-c3d16ad # v1.6.65 with: allow_failure: true prefix_mode: true @@ -33,7 +33,7 @@ jobs: - name: Backport Action if: steps.preview_label_check.outputs.label_check == 'success' - uses: sorenlouv/backport-github-action@v9.5.1 + uses: sorenlouv/backport-github-action@ad888e978060bc1b2798690dd9d03c4036560947 # v9.5.1 with: github_token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} auto_backport_label_prefix: ${{ env.BACKPORT_LABEL_PREFIX }} diff --git a/.github/workflows/build-documentation-on-pr.yml b/.github/workflows/build-documentation-on-pr.yml index 7ae58b9c85..25fc2910f9 100644 --- a/.github/workflows/build-documentation-on-pr.yml +++ b/.github/workflows/build-documentation-on-pr.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Leave PR comment with the Prowler Documentation URI - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 with: issue-number: ${{ env.PR_NUMBER }} body: | diff --git a/.github/workflows/conventional-commit.yml b/.github/workflows/conventional-commit.yml index 0a45e7fd30..cdc3e52de5 100644 --- a/.github/workflows/conventional-commit.yml +++ b/.github/workflows/conventional-commit.yml @@ -18,6 +18,6 @@ jobs: steps: - name: conventional-commit-check id: conventional-commit-check - uses: agenthunt/conventional-commit-checker-action@v2.0.0 + uses: agenthunt/conventional-commit-checker-action@9e552d650d0e205553ec7792d447929fc78e012b # v2.0.0 with: pr-title-regex: '^([^\s(]+)(?:\(([^)]+)\))?: (.+)' diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml index 66f8f1802c..aade5f3ba4 100644 --- a/.github/workflows/find-secrets.yml +++ b/.github/workflows/find-secrets.yml @@ -7,11 +7,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@v3.88.16 + uses: trufflesecurity/trufflehog@12164e38f0f1b673ab0594c7d94daf71b0be6823 # v3.88.17 with: path: ./ base: ${{ github.event.repository.default_branch }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 199b17962d..6507474ec8 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -14,4 +14,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml index 4536430255..e3629f2d46 100644 --- a/.github/workflows/sdk-build-lint-push-containers.yml +++ b/.github/workflows/sdk-build-lint-push-containers.yml @@ -59,10 +59,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ env.PYTHON_VERSION }} @@ -108,13 +108,13 @@ jobs: esac - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Public ECR - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: public.ecr.aws username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }} @@ -123,11 +123,11 @@ jobs: AWS_REGION: ${{ env.AWS_REGION }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build and push container image (latest) if: github.event_name == 'push' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: push: true tags: | @@ -140,7 +140,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: # Use local context to get changes # https://github.com/docker/build-push-action#path-context diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index 1c5663de5b..5f1d8fd1c1 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -50,16 +50,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/sdk-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 646277dec5..5fee5003bf 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -21,11 +21,11 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@v45 + uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 with: files: ./** files_ignore: | @@ -50,7 +50,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" @@ -113,7 +113,7 @@ jobs: - name: Upload coverage reports to Codecov if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml index af44300179..9c707538f4 100644 --- a/.github/workflows/sdk-pypi-release.yml +++ b/.github/workflows/sdk-pypi-release.yml @@ -64,14 +64,14 @@ jobs: ;; esac - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install dependencies run: | pipx install poetry==1.8.5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ env.PYTHON_VERSION }} cache: ${{ env.CACHE }} diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index bf7af302e2..71e8aac4b0 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -23,12 +23,12 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ env.GITHUB_BRANCH }} - name: setup python - uses: actions/setup-python@v5 + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: 3.9 #install the python needed @@ -38,7 +38,7 @@ jobs: pip install boto3 - name: Configure AWS Credentials -- DEV - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: aws-region: ${{ env.AWS_REGION_DEV }} role-to-assume: ${{ secrets.DEV_IAM_ROLE_ARN }} @@ -50,7 +50,7 @@ jobs: # Create pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} commit-message: "feat(regions_update): Update regions for AWS services" diff --git a/.github/workflows/ui-build-lint-push-containers.yml b/.github/workflows/ui-build-lint-push-containers.yml index 572f06d027..8d14ae0bbe 100644 --- a/.github/workflows/ui-build-lint-push-containers.yml +++ b/.github/workflows/ui-build-lint-push-containers.yml @@ -61,7 +61,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set short git commit SHA id: vars @@ -70,18 +70,18 @@ jobs: echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build and push container image (latest) # Comment the following line for testing if: github.event_name == 'push' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.WORKING_DIRECTORY }} build-args: | @@ -96,7 +96,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.WORKING_DIRECTORY }} build-args: | @@ -110,7 +110,7 @@ jobs: - name: Trigger deployment if: github.event_name == 'push' - uses: peter-evans/repository-dispatch@v3 + uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} repository: ${{ secrets.CLOUD_DISPATCH }} diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml index 6192713d39..d0f3603430 100644 --- a/.github/workflows/ui-codeql.yml +++ b/.github/workflows/ui-codeql.yml @@ -44,16 +44,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/ui-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ui-pull-request.yml b/.github/workflows/ui-pull-request.yml index 79e4c5e54b..b8967c4324 100644 --- a/.github/workflows/ui-pull-request.yml +++ b/.github/workflows/ui-pull-request.yml @@ -27,11 +27,11 @@ jobs: node-version: [20.x] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ matrix.node-version }} - name: Install dependencies @@ -46,11 +46,11 @@ jobs: test-container-build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build Container - uses: docker/build-push-action@v6 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: ${{ env.UI_WORKING_DIR }} # Always build using `prod` target From 97da78d4e7e9239f2534340ee2553f96db04d5bb Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 17 Mar 2025 18:19:43 +0545 Subject: [PATCH 016/359] fix(backport): Use container tagged version (#7252) --- .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 e825a8de49..2aa0a49c09 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Check labels id: preview_label_check - uses: docker://agilepathway/pull-request-label-checker:sha-c3d16ad # v1.6.65 + uses: agilepathway/label-checker@c3d16ad512e7cea5961df85ff2486bb774caf3c5 # v1.6.65 with: allow_failure: true prefix_mode: true From a7f55d06afea174d7c4d483f2ae5a0a1015a382c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 17 Mar 2025 14:31:35 +0100 Subject: [PATCH 017/359] feat(jira): add basic auth method (#7233) --- .../lib/outputs/jira/exceptions/exceptions.py | 22 +++ prowler/lib/outputs/jira/jira.py | 129 ++++++++++++++++-- tests/lib/outputs/jira/jira_test.py | 87 ++++++++++++ 3 files changed, 224 insertions(+), 14 deletions(-) diff --git a/prowler/lib/outputs/jira/exceptions/exceptions.py b/prowler/lib/outputs/jira/exceptions/exceptions.py index a8267ffba6..ed138a73a4 100644 --- a/prowler/lib/outputs/jira/exceptions/exceptions.py +++ b/prowler/lib/outputs/jira/exceptions/exceptions.py @@ -82,6 +82,14 @@ class JiraBaseException(ProwlerException): "message": "The project key is invalid.", "remediation": "Please check the project key and try again.", }, + (9019, "JiraBasicAuthError"): { + "message": "Failed to authenticate with Jira using basic authentication.", + "remediation": "Please check the user mail and API token and try again.", + }, + (9020, "JiraInvalidParameterError"): { + "message": "Missing parameters on Jira Init function.", + "remediation": "Please check the parameters and try again.", + }, } def __init__(self, code, file=None, original_exception=None, message=None): @@ -229,3 +237,17 @@ class JiraInvalidProjectKeyError(JiraBaseException): super().__init__( 9018, file=file, original_exception=original_exception, message=message ) + + +class JiraBasicAuthError(JiraBaseException): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 9019, file=file, original_exception=original_exception, message=message + ) + + +class JiraInvalidParameterError(JiraBaseException): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 9020, file=file, original_exception=original_exception, message=message + ) diff --git a/prowler/lib/outputs/jira/jira.py b/prowler/lib/outputs/jira/jira.py index 34629b7e42..616f97b820 100644 --- a/prowler/lib/outputs/jira/jira.py +++ b/prowler/lib/outputs/jira/jira.py @@ -10,6 +10,7 @@ from prowler.lib.logger import logger from prowler.lib.outputs.finding import Finding from prowler.lib.outputs.jira.exceptions.exceptions import ( JiraAuthenticationError, + JiraBasicAuthError, JiraCreateIssueError, JiraGetAccessTokenError, JiraGetAuthResponseError, @@ -21,6 +22,7 @@ from prowler.lib.outputs.jira.exceptions.exceptions import ( JiraGetProjectsError, JiraGetProjectsResponseError, JiraInvalidIssueTypeError, + JiraInvalidParameterError, JiraInvalidProjectKeyError, JiraNoProjectsError, JiraNoTokenError, @@ -84,6 +86,8 @@ class Jira: - JiraCreateIssueError: Failed to create an issue in Jira - JiraSendFindingsResponseError: Failed to send the findings to Jira - JiraTestConnectionError: Failed to test the connection + - JiraBasicAuthError: Failed to authenticate using basic auth + - JiraInvalidParameterError: The provided parameters in Init are invalid Usage: jira = Jira( @@ -98,6 +102,10 @@ class Jira: _client_id: str = None _client_secret: str = None _access_token: str = None + _user_mail: str = None + _api_token: str = None + _domain: str = None + _using_basic_auth: bool = False _refresh_token: str = None _expiration_date: int = None _cloud_id: str = None @@ -120,14 +128,31 @@ class Jira: redirect_uri: str = None, client_id: str = None, client_secret: str = None, + user_mail: str = None, + api_token: str = None, + domain: str = None, ): self._redirect_uri = redirect_uri self._client_id = client_id self._client_secret = client_secret + self._user_mail = user_mail + self._api_token = api_token + self._domain = domain self._scopes = ["read:jira-user", "read:jira-work", "write:jira-work"] - auth_url = self.auth_code_url() - authorization_code = self.input_authorization_code(auth_url) - self.get_auth(authorization_code) + # If the client mail, API token and site name are present, use basic auth + if user_mail and api_token and domain: + self._using_basic_auth = True + self.get_basic_auth() + # If the redirect URI, client ID and client secret are present, use auth code flow + elif redirect_uri and client_id and client_secret: + auth_url = self.auth_code_url() + authorization_code = self.input_authorization_code(auth_url) + self.get_auth(authorization_code) + else: + init_error = "Failed to initialize Jira object, missing parameters." + raise JiraInvalidParameterError( + message=init_error, file=os.path.basename(__file__) + ) @property def redirect_uri(self): @@ -157,6 +182,10 @@ class Jira: def scopes(self): return self._scopes + @property + def using_basic_auth(self): + return self._using_basic_auth + def get_params(self, state_encoded): return { **self.PARAMS_TEMPLATE, @@ -209,6 +238,29 @@ class Jira: """ return (datetime.now() + timedelta(seconds=seconds)).isoformat() + def get_basic_auth(self) -> None: + """Get the access token using the mail and API token. + + Returns: + - None + + Raises: + - JiraBasicAuthError: Failed to authenticate using basic auth + """ + try: + user_string = f"{self._user_mail}:{self._api_token}" + self._access_token = base64.b64encode(user_string.encode("utf-8")).decode( + "utf-8" + ) + self._cloud_id = self.get_cloud_id(self._access_token, domain=self._domain) + except Exception as e: + message_error = f"Failed to get auth using basic auth: {e}" + logger.error(message_error) + raise JiraBasicAuthError( + message=message_error, + file=os.path.basename(__file__), + ) + def get_auth(self, auth_code: str = None) -> None: """Get the access token and refresh token @@ -269,11 +321,12 @@ class Jira: file=os.path.basename(__file__), ) - def get_cloud_id(self, access_token: str = None) -> str: + def get_cloud_id(self, access_token: str = None, domain: str = None) -> str: """Get the cloud ID from Jira Args: - access_token: The access token from Jira + - domain: The site name from Jira Returns: - str: The cloud ID @@ -284,8 +337,17 @@ class Jira: - JiraGetCloudIDError: Failed to get the cloud ID from Jira """ try: - headers = {"Authorization": f"Bearer {access_token}"} - response = requests.get(self.API_TOKEN_URL, headers=headers) + if self._using_basic_auth: + headers = {"Authorization": f"Basic {access_token}"} + response = requests.get( + f"https://{domain}.atlassian.net/_edge/tenant_info", + headers=headers, + ) + response = response.json() + return response.get("cloudId") + else: + headers = {"Authorization": f"Bearer {access_token}"} + response = requests.get(self.API_TOKEN_URL, headers=headers) if response.status_code == 200: resources = response.json() @@ -326,6 +388,10 @@ class Jira: - JiraGetAccessTokenError: Failed to get the access token """ try: + # If using basic auth, return the access token + if self._using_basic_auth: + return self._access_token + if self.auth_expiration and datetime.now() < datetime.fromisoformat( self.auth_expiration ): @@ -392,6 +458,9 @@ class Jira: redirect_uri: str = None, client_id: str = None, client_secret: str = None, + user_mail: str = None, + api_token: str = None, + domain: str = None, raise_on_exception: bool = True, ) -> Connection: """Test the connection to Jira @@ -400,6 +469,9 @@ class Jira: - redirect_uri: The redirect URI - client_id: The client ID - client_secret: The client secret + - user_mail: The client mail + - api_token: The API token + - domain: The site name - raise_on_exception: Whether to raise an exception or not Returns: @@ -417,13 +489,20 @@ class Jira: redirect_uri=redirect_uri, client_id=client_id, client_secret=client_secret, + user_mail=user_mail, + api_token=api_token, + domain=domain, ) access_token = jira.get_access_token() if not access_token: return ValueError("Failed to get access token") - headers = {"Authorization": f"Bearer {access_token}"} + if jira.using_basic_auth: + headers = {"Authorization": f"Basic {access_token}"} + else: + headers = {"Authorization": f"Bearer {access_token}"} + response = requests.get( f"https://api.atlassian.com/ex/jira/{jira.cloud_id}/rest/api/3/myself", headers=headers, @@ -461,6 +540,13 @@ class Jira: if raise_on_exception: raise auth_error return Connection(error=auth_error) + except JiraBasicAuthError as basic_auth_error: + logger.error( + f"{basic_auth_error.__class__.__name__}[{basic_auth_error.__traceback__.tb_lineno}]: {basic_auth_error}" + ) + if raise_on_exception: + raise basic_auth_error + return Connection(error=basic_auth_error) except Exception as error: logger.error(f"Failed to test connection: {error}") if raise_on_exception: @@ -489,7 +575,11 @@ class Jira: if not access_token: return ValueError("Failed to get access token") - headers = {"Authorization": f"Bearer {access_token}"} + if self._using_basic_auth: + headers = {"Authorization": f"Basic {access_token}"} + else: + headers = {"Authorization": f"Bearer {access_token}"} + response = requests.get( f"https://api.atlassian.com/ex/jira/{self.cloud_id}/rest/api/3/project", headers=headers, @@ -500,7 +590,7 @@ class Jira: projects = { project["key"]: project["name"] for project in response.json() } - if len(projects) == 0: + if projects == {}: # If no projects are found logger.error("No projects found") raise JiraNoProjectsError( message="No projects found in Jira", @@ -555,7 +645,11 @@ class Jira: file=os.path.basename(__file__), ) - headers = {"Authorization": f"Bearer {access_token}"} + if self._using_basic_auth: + headers = {"Authorization": f"Basic {access_token}"} + else: + headers = {"Authorization": f"Bearer {access_token}"} + response = requests.get( f"https://api.atlassian.com/ex/jira/{self.cloud_id}/rest/api/3/issue/createmeta?projectKeys={project_key}&expand=projects.issuetypes.fields", headers=headers, @@ -1109,10 +1203,17 @@ class Jira: raise JiraInvalidIssueTypeError( message="The issue type is invalid", file=os.path.basename(__file__) ) - headers = { - "Authorization": f"Bearer {access_token}", - "Content-Type": "application/json", - } + + if self._using_basic_auth: + headers = { + "Authorization": f"Basic {access_token}", + "Content-Type": "application/json", + } + else: + headers = { + "Authorization": f"Bearer {access_token}", + "Content-Type": "application/json", + } for finding in findings: status_color = self.get_color_from_status(finding.status.value) diff --git a/tests/lib/outputs/jira/jira_test.py b/tests/lib/outputs/jira/jira_test.py index 238f433894..e4cc7fbc0b 100644 --- a/tests/lib/outputs/jira/jira_test.py +++ b/tests/lib/outputs/jira/jira_test.py @@ -1,3 +1,4 @@ +import base64 from datetime import datetime, timedelta from unittest.mock import MagicMock, PropertyMock, patch from urllib.parse import parse_qs, urlparse @@ -7,6 +8,7 @@ from freezegun import freeze_time from prowler.lib.outputs.jira.exceptions.exceptions import ( JiraAuthenticationError, + JiraBasicAuthError, JiraCreateIssueError, JiraGetAvailableIssueTypesError, JiraGetCloudIDError, @@ -39,6 +41,22 @@ class TestJiraIntegration: client_secret=self.client_secret, ) + @pytest.fixture(autouse=True) + @patch.object(Jira, "get_basic_auth", return_value=None) + def setup_basic_auth(self, mock_get_basic_auth): + # To disable vulture + mock_get_basic_auth = mock_get_basic_auth + + self.user_mail = "test_user_mail" + self.api_token = "test_api_token" + self.domain = "test_domain" + + self.jira_integration_basic_auth = Jira( + user_mail=self.user_mail, + api_token=self.api_token, + domain=self.domain, + ) + @patch.object(Jira, "get_auth", return_value=None) def test_auth_code_url(self, mock_get_auth): """Test to verify the authorization URL generation with correct query parameters""" @@ -68,6 +86,31 @@ class TestJiraIntegration: assert query_params["response_type"][0] == "code" assert query_params["prompt"][0] == "consent" + @patch.object(Jira, "get_cloud_id", return_value="test_cloud_id") + def test_get_auth_successful_basic_auth(self, mock_get_cloud_id): + """Test successful token retrieval in get_basic_auth.""" + # To disable vulture + mock_get_cloud_id = mock_get_cloud_id + + self.jira_integration_basic_auth.get_basic_auth() + + user_string = "test_user_mail:test_api_token" + user_string_base64 = base64.b64encode(user_string.encode("utf-8")).decode( + "utf-8" + ) + + assert self.jira_integration_basic_auth._access_token == user_string_base64 + assert self.jira_integration_basic_auth._cloud_id == "test_cloud_id" + + @patch.object(Jira, "get_cloud_id", side_effect=Exception("Connection error")) + def test_get_auth_error_basic_auth(self, mock_get_cloud_id): + """Test successful token retrieval in get_basic_auth.""" + # To disable vulture + mock_get_cloud_id = mock_get_cloud_id + + with pytest.raises(JiraBasicAuthError): + self.jira_integration_basic_auth.get_basic_auth() + @freeze_time(TEST_DATETIME) @patch("prowler.lib.outputs.jira.jira.requests.post") @patch.object(Jira, "get_cloud_id", return_value="test_cloud_id") @@ -276,6 +319,33 @@ class TestJiraIntegration: assert connection.is_connected assert connection.error is None + @patch.object(Jira, "get_access_token", return_value="valid_access_token") + @patch.object(Jira, "get_cloud_id", return_value="test_cloud_id") + @patch.object(Jira, "get_basic_auth", return_value=None) + @patch("prowler.lib.outputs.jira.jira.requests.get") + def test_test_connection_successful_basic_auth( + self, mock_get, mock_get_cloud_id, mock_get_auth, mock_get_access_token + ): + """Test that a successful connection returns an active Connection object.""" + # To disable vulture + mock_get_cloud_id = mock_get_cloud_id + mock_get_auth = mock_get_auth + mock_get_access_token = mock_get_access_token + + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = {"id": "test_user_id"} + mock_get.return_value = mock_response + + connection = self.jira_integration_basic_auth.test_connection( + user_mail=self.user_mail, + api_token=self.api_token, + domain=self.domain, + ) + + assert connection.is_connected + assert connection.error is None + @patch.object( Jira, "get_access_token", @@ -293,6 +363,23 @@ class TestJiraIntegration: client_secret=self.client_secret, ) + @patch.object( + Jira, + "get_cloud_id", + side_effect=JiraBasicAuthError("Failed to authenticate with Jira"), + ) + def test_test_connection_failed_basic_auth(self, mock_get_access_token): + """Test that a failed connection raises JiraAuthenticationError.""" + # To disable vulture + mock_get_access_token = mock_get_access_token + + with pytest.raises(JiraBasicAuthError): + self.jira_integration_basic_auth.test_connection( + user_mail=self.user_mail, + api_token=self.api_token, + domain=self.domain, + ) + @patch.object(Jira, "get_access_token", return_value="valid_access_token") @patch.object( Jira, "cloud_id", new_callable=PropertyMock, return_value="test_cloud_id" From 72de5fdb1b4696d28578b801ae253d370a04c765 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 17 Mar 2025 14:53:58 +0100 Subject: [PATCH 018/359] chore: update git ignore file (#7254) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 53d24facf6..17a6e736b5 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ junit-reports/ # .env ui/.env* api/.env* +.env.local # Coverage .coverage* From 6a4df15c47c3febc2669bc80a990a7e8a65306bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 17 Mar 2025 15:44:15 +0100 Subject: [PATCH 019/359] fix(prowler): change from prowler.py to prowler-cli.py (#7253) --- README.md | 2 +- contrib/aws/org-multi-account/src/run-prowler-reports.sh | 2 +- contrib/k8s/cronjob.yml | 2 +- docs/developer-guide/debugging.md | 8 ++++---- docs/index.md | 2 +- docs/tutorials/aws/cloudshell.md | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cb40861994..c1b238fff5 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ git clone https://github.com/prowler-cloud/prowler cd prowler eval $(poetry env activate) poetry install -python prowler.py -v +python prowler-cli.py -v ``` > [!IMPORTANT] > Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`. diff --git a/contrib/aws/org-multi-account/src/run-prowler-reports.sh b/contrib/aws/org-multi-account/src/run-prowler-reports.sh index 350ceefb6b..b7488b12e2 100644 --- a/contrib/aws/org-multi-account/src/run-prowler-reports.sh +++ b/contrib/aws/org-multi-account/src/run-prowler-reports.sh @@ -89,7 +89,7 @@ for accountId in $ACCOUNTS_IN_ORGS; do # Run Prowler echo -e "Assessing AWS Account: $accountId, using Role: $ROLE on $(date)" # remove -g cislevel for a full report and add other formats if needed - ./prowler/prowler.py --role arn:"$PARTITION":iam::"$accountId":role/"$ROLE" --compliance cis_1.5_aws -M html + ./prowler/prowler-cli.py --role arn:"$PARTITION":iam::"$accountId":role/"$ROLE" --compliance cis_1.5_aws -M html echo "Report stored locally at: prowler/output/ directory" TOTAL_SEC=$((SECONDS - START_TIME)) echo -e "Completed AWS Account: $accountId, using Role: $ROLE on $(date)" diff --git a/contrib/k8s/cronjob.yml b/contrib/k8s/cronjob.yml index 26bf13a6b5..87ad6d05f2 100644 --- a/contrib/k8s/cronjob.yml +++ b/contrib/k8s/cronjob.yml @@ -17,7 +17,7 @@ spec: image: toniblyx/prowler:latest imagePullPolicy: Always command: - - "./prowler.py" + - "./prowler-cli.py" args: [ "-B", "$(awsS3Bucket)" ] env: - name: AWS_ACCESS_KEY_ID diff --git a/docs/developer-guide/debugging.md b/docs/developer-guide/debugging.md index 33c0849f49..bf51d313c1 100644 --- a/docs/developer-guide/debugging.md +++ b/docs/developer-guide/debugging.md @@ -18,7 +18,7 @@ This file should inside the *.vscode* folder and its name has to be *launch.json "name": "Debug AWS Check", "type": "debugpy", "request": "launch", - "program": "prowler.py", + "program": "prowler-cli.py", "args": [ "aws", "--log-level", @@ -33,7 +33,7 @@ This file should inside the *.vscode* folder and its name has to be *launch.json "name": "Debug Azure Check", "type": "debugpy", "request": "launch", - "program": "prowler.py", + "program": "prowler-cli.py", "args": [ "azure", "--sp-env-auth", @@ -49,7 +49,7 @@ This file should inside the *.vscode* folder and its name has to be *launch.json "name": "Debug GCP Check", "type": "debugpy", "request": "launch", - "program": "prowler.py", + "program": "prowler-cli.py", "args": [ "gcp", "--log-level", @@ -64,7 +64,7 @@ This file should inside the *.vscode* folder and its name has to be *launch.json "name": "Debug K8s Check", "type": "debugpy", "request": "launch", - "program": "prowler.py", + "program": "prowler-cli.py", "args": [ "kubernetes", "--log-level", diff --git a/docs/index.md b/docs/index.md index 27376ecc29..628f9bf7ce 100644 --- a/docs/index.md +++ b/docs/index.md @@ -219,7 +219,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), git clone https://github.com/prowler-cloud/prowler cd prowler poetry install - poetry run python prowler.py -v + poetry run python prowler-cli.py -v ``` ???+ note If you want to clone Prowler from Windows, use `git config core.longpaths true` to allow long file paths. diff --git a/docs/tutorials/aws/cloudshell.md b/docs/tutorials/aws/cloudshell.md index d40b0dd9b4..0e02ea5da4 100644 --- a/docs/tutorials/aws/cloudshell.md +++ b/docs/tutorials/aws/cloudshell.md @@ -29,7 +29,7 @@ mkdir /tmp/poetry poetry config cache-dir /tmp/poetry eval $(poetry env activate) poetry install -python prowler.py -v +python prowler-cli.py -v ``` > [!IMPORTANT] > Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`. From f6aa56d92b782843ac89ca33ff552e945b53b47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 17 Mar 2025 16:03:55 +0100 Subject: [PATCH 020/359] fix(.env): remove spaces (#7255) --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index ef04a95338..23d6f30721 100644 --- a/.env +++ b/.env @@ -33,10 +33,10 @@ VALKEY_DB=0 # API scan settings # The path to the directory where scan output should be stored -DJANGO_TMP_OUTPUT_DIRECTORY = "/tmp/prowler_api_output" +DJANGO_TMP_OUTPUT_DIRECTORY="/tmp/prowler_api_output" # The maximum number of findings to process in a single batch -DJANGO_FINDINGS_BATCH_SIZE = 1000 +DJANGO_FINDINGS_BATCH_SIZE=1000 # The AWS access key to be used when uploading scan output to an S3 bucket # If left empty, default AWS credentials resolution behavior will be used From d5be35af4939fa049647ecf4d432c75b0dd771b8 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 17 Mar 2025 16:26:27 +0100 Subject: [PATCH 021/359] chore: Rename keyServer and extract to helper (#7256) --- ui/actions/auth/auth.ts | 10 +-- ui/actions/compliances/compliances.ts | 5 +- ui/actions/findings/findings.ts | 8 +- ui/actions/invitations/invitation.ts | 17 ++-- ui/actions/manage-groups/manage-groups.ts | 17 ++-- ui/actions/overview/overview.ts | 11 +-- ui/actions/providers/providers.ts | 29 +++---- ui/actions/roles/roles.ts | 17 ++-- ui/actions/scans/scans.ts | 23 ++---- ui/actions/services/index.ts | 1 - ui/actions/services/services.ts | 97 ----------------------- ui/actions/task/tasks.ts | 5 +- ui/actions/users/users.ts | 17 ++-- ui/app/(prowler)/services/page.tsx | 32 +------- ui/app/api/auth/callback/github/route.ts | 6 +- ui/app/api/auth/callback/google/route.ts | 6 +- ui/auth.config.ts | 4 +- ui/lib/helper.ts | 1 + 18 files changed, 68 insertions(+), 238 deletions(-) delete mode 100644 ui/actions/services/index.ts delete mode 100644 ui/actions/services/services.ts diff --git a/ui/actions/auth/auth.ts b/ui/actions/auth/auth.ts index d39314d2da..e0e3a75e20 100644 --- a/ui/actions/auth/auth.ts +++ b/ui/actions/auth/auth.ts @@ -4,6 +4,7 @@ import { AuthError } from "next-auth"; import { z } from "zod"; import { signIn, signOut } from "@/auth.config"; +import { apiBaseUrl } from "@/lib"; import { authFormSchema } from "@/types"; const formSchemaSignIn = authFormSchema("sign-in"); @@ -57,8 +58,7 @@ export async function authenticate( export const createNewUser = async ( formData: z.infer, ) => { - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/users`); + const url = new URL(`${apiBaseUrl}/users`); if (formData.invitationToken) { url.searchParams.append("invitation_token", formData.invitationToken); @@ -105,8 +105,7 @@ export const createNewUser = async ( }; export const getToken = async (formData: z.infer) => { - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/tokens`); + const url = new URL(`${apiBaseUrl}/tokens`); const bodyData = { data: { @@ -144,8 +143,7 @@ export const getToken = async (formData: z.infer) => { }; export const getUserByMe = async (accessToken: string) => { - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/users/me`); + const url = new URL(`${apiBaseUrl}/users/me`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/compliances/compliances.ts b/ui/actions/compliances/compliances.ts index 5eb94cde98..a89c932d91 100644 --- a/ui/actions/compliances/compliances.ts +++ b/ui/actions/compliances/compliances.ts @@ -2,7 +2,7 @@ import { revalidatePath } from "next/cache"; import { auth } from "@/auth.config"; -import { parseStringify } from "@/lib"; +import { apiBaseUrl, parseStringify } from "@/lib"; export const getCompliancesOverview = async ({ scanId, @@ -15,8 +15,7 @@ export const getCompliancesOverview = async ({ }) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/compliance-overviews`); + const url = new URL(`${apiBaseUrl}/compliance-overviews`); if (scanId) url.searchParams.append("filter[scan_id]", scanId); if (query) url.searchParams.append("filter[search]", query); diff --git a/ui/actions/findings/findings.ts b/ui/actions/findings/findings.ts index 901228a91a..b4c804e43c 100644 --- a/ui/actions/findings/findings.ts +++ b/ui/actions/findings/findings.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { parseStringify } from "@/lib"; +import { apiBaseUrl, parseStringify } from "@/lib"; export const getFindings = async ({ page = 1, @@ -18,8 +18,7 @@ export const getFindings = async ({ if (isNaN(Number(page)) || page < 1) redirect("findings?include=resources,scan.provider"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/findings?include=resources,scan.provider`); + const url = new URL(`${apiBaseUrl}/findings?include=resources,scan.provider`); if (page) url.searchParams.append("page[number]", page.toString()); if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); @@ -56,8 +55,7 @@ export const getMetadataInfo = async ({ }) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/findings/metadata`); + const url = new URL(`${apiBaseUrl}/findings/metadata`); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/invitations/invitation.ts b/ui/actions/invitations/invitation.ts index 28ef77c9e2..d1908f21da 100644 --- a/ui/actions/invitations/invitation.ts +++ b/ui/actions/invitations/invitation.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; export const getInvitations = async ({ page = 1, @@ -16,8 +16,7 @@ export const getInvitations = async ({ if (isNaN(Number(page)) || page < 1) redirect("/invitations"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/tenants/invitations`); + const url = new URL(`${apiBaseUrl}/tenants/invitations`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -50,11 +49,10 @@ export const getInvitations = async ({ export const sendInvite = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const email = formData.get("email"); const role = formData.get("role"); - const url = new URL(`${keyServer}/tenants/invitations`); + const url = new URL(`${apiBaseUrl}/tenants/invitations`); const body = JSON.stringify({ data: { @@ -99,7 +97,6 @@ export const sendInvite = async (formData: FormData) => { export const updateInvite = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const invitationId = formData.get("invitationId"); const invitationEmail = formData.get("invitationEmail"); @@ -108,7 +105,7 @@ export const updateInvite = async (formData: FormData) => { formData.get("expires_at") || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(); - const url = new URL(`${keyServer}/tenants/invitations/${invitationId}`); + const url = new URL(`${apiBaseUrl}/tenants/invitations/${invitationId}`); const body: any = { data: { @@ -165,8 +162,7 @@ export const updateInvite = async (formData: FormData) => { export const getInvitationInfoById = async (invitationId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/tenants/invitations/${invitationId}`); + const url = new URL(`${apiBaseUrl}/tenants/invitations/${invitationId}`); try { const response = await fetch(url.toString(), { @@ -188,14 +184,13 @@ export const getInvitationInfoById = async (invitationId: string) => { export const revokeInvite = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const invitationId = formData.get("invitationId"); if (!invitationId) { return { error: "Invitation ID is required" }; } - const url = new URL(`${keyServer}/tenants/invitations/${invitationId}`); + const url = new URL(`${apiBaseUrl}/tenants/invitations/${invitationId}`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/manage-groups/manage-groups.ts b/ui/actions/manage-groups/manage-groups.ts index 13b29534ae..7ed92989c8 100644 --- a/ui/actions/manage-groups/manage-groups.ts +++ b/ui/actions/manage-groups/manage-groups.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; import { ManageGroupPayload, ProviderGroupsResponse } from "@/types/components"; export const getProviderGroups = async ({ @@ -22,8 +22,7 @@ export const getProviderGroups = async ({ if (isNaN(Number(page)) || page < 1) redirect("/manage-groups"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/provider-groups`); + const url = new URL(`${apiBaseUrl}/provider-groups`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -61,8 +60,7 @@ export const getProviderGroups = async ({ export const getProviderGroupInfoById = async (providerGroupId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/provider-groups/${providerGroupId}`); + const url = new URL(`${apiBaseUrl}/provider-groups/${providerGroupId}`); try { const response = await fetch(url.toString(), { @@ -90,7 +88,6 @@ export const getProviderGroupInfoById = async (providerGroupId: string) => { export const createProviderGroup = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const name = formData.get("name") as string; const providersJson = formData.get("providers") as string; @@ -127,7 +124,7 @@ export const createProviderGroup = async (formData: FormData) => { const body = JSON.stringify(payload); try { - const url = new URL(`${keyServer}/provider-groups`); + const url = new URL(`${apiBaseUrl}/provider-groups`); const response = await fetch(url.toString(), { method: "POST", headers: { @@ -152,7 +149,6 @@ export const updateProviderGroup = async ( formData: FormData, ) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const name = formData.get("name") as string; const providersJson = formData.get("providers") as string; @@ -180,7 +176,7 @@ export const updateProviderGroup = async ( } try { - const url = `${keyServer}/provider-groups/${providerGroupId}`; + const url = `${apiBaseUrl}/provider-groups/${providerGroupId}`; const response = await fetch(url, { method: "PATCH", headers: { @@ -209,14 +205,13 @@ export const updateProviderGroup = async ( export const deleteProviderGroup = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerGroupId = formData.get("id"); if (!providerGroupId) { return { error: "Provider Group ID is required" }; } - const url = new URL(`${keyServer}/provider-groups/${providerGroupId}`); + const url = new URL(`${apiBaseUrl}/provider-groups/${providerGroupId}`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/overview.ts b/ui/actions/overview/overview.ts index 2095a9f32f..ef591ee11f 100644 --- a/ui/actions/overview/overview.ts +++ b/ui/actions/overview/overview.ts @@ -3,7 +3,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { parseStringify } from "@/lib"; +import { apiBaseUrl, parseStringify } from "@/lib"; export const getProvidersOverview = async ({ page = 1, @@ -15,8 +15,7 @@ export const getProvidersOverview = async ({ if (isNaN(Number(page)) || page < 1) redirect("/providers-overview"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/overviews/providers`); + const url = new URL(`${apiBaseUrl}/overviews/providers`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -58,8 +57,7 @@ export const getFindingsByStatus = async ({ if (isNaN(Number(page)) || page < 1) redirect("/"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/overviews/findings`); + const url = new URL(`${apiBaseUrl}/overviews/findings`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -105,8 +103,7 @@ export const getFindingsBySeverity = async ({ if (isNaN(Number(page)) || page < 1) redirect("/"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/overviews/findings_severity`); + const url = new URL(`${apiBaseUrl}/overviews/findings_severity`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 0ac39db2d6..5289eb5205 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify, wait } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify, wait } from "@/lib"; export const getProviders = async ({ page = 1, @@ -16,8 +16,7 @@ export const getProviders = async ({ if (isNaN(Number(page)) || page < 1) redirect("/providers"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/providers?include=provider_groups`); + const url = new URL(`${apiBaseUrl}/providers?include=provider_groups`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -52,8 +51,7 @@ export const getProvider = async (formData: FormData) => { const session = await auth(); const providerId = formData.get("id"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/providers/${providerId}`); + const url = new URL(`${apiBaseUrl}/providers/${providerId}`); try { const providers = await fetch(url.toString(), { @@ -74,12 +72,11 @@ export const getProvider = async (formData: FormData) => { export const updateProvider = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerId = formData.get("providerId"); const providerAlias = formData.get("alias"); - const url = new URL(`${keyServer}/providers/${providerId}`); + const url = new URL(`${apiBaseUrl}/providers/${providerId}`); try { const response = await fetch(url.toString(), { @@ -113,13 +110,12 @@ export const updateProvider = async (formData: FormData) => { export const addProvider = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerType = formData.get("providerType") as string; const providerUid = formData.get("providerUid") as string; const providerAlias = formData.get("providerAlias") as string; - const url = new URL(`${keyServer}/providers`); + const url = new URL(`${apiBaseUrl}/providers`); try { const bodyData = { @@ -157,8 +153,7 @@ export const addProvider = async (formData: FormData) => { export const addCredentialsProvider = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/providers/secrets`); + const url = new URL(`${apiBaseUrl}/providers/secrets`); const secretName = formData.get("secretName"); const providerId = formData.get("providerId"); @@ -259,8 +254,7 @@ export const updateCredentialsProvider = async ( formData: FormData, ) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/providers/secrets/${credentialsId}`); + const url = new URL(`${apiBaseUrl}/providers/secrets/${credentialsId}`); const secretName = formData.get("secretName"); const providerType = formData.get("providerType"); @@ -352,11 +346,10 @@ export const updateCredentialsProvider = async ( export const checkConnectionProvider = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerId = formData.get("providerId"); - const url = new URL(`${keyServer}/providers/${providerId}/connection`); + const url = new URL(`${apiBaseUrl}/providers/${providerId}/connection`); try { const response = await fetch(url.toString(), { @@ -379,13 +372,12 @@ export const checkConnectionProvider = async (formData: FormData) => { export const deleteCredentials = async (secretId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; if (!secretId) { return { error: "Secret ID is required" }; } - const url = new URL(`${keyServer}/providers/secrets/${secretId}`); + const url = new URL(`${apiBaseUrl}/providers/secrets/${secretId}`); try { const response = await fetch(url.toString(), { @@ -422,14 +414,13 @@ export const deleteCredentials = async (secretId: string) => { export const deleteProvider = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerId = formData.get("id"); if (!providerId) { return { error: "Provider ID is required" }; } - const url = new URL(`${keyServer}/providers/${providerId}`); + const url = new URL(`${apiBaseUrl}/providers/${providerId}`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index a371fd74ea..8f7cbde0fb 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; export const getRoles = async ({ page = 1, @@ -16,8 +16,7 @@ export const getRoles = async ({ if (isNaN(Number(page)) || page < 1) redirect("/roles"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/roles`); + const url = new URL(`${apiBaseUrl}/roles`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -50,8 +49,7 @@ export const getRoles = async ({ export const getRoleInfoById = async (roleId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/roles/${roleId}`); + const url = new URL(`${apiBaseUrl}/roles/${roleId}`); try { const response = await fetch(url.toString(), { @@ -77,7 +75,6 @@ export const getRoleInfoById = async (roleId: string) => { export const addRole = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const name = formData.get("name") as string; const groups = formData.getAll("groups[]") as string[]; @@ -118,7 +115,7 @@ export const addRole = async (formData: FormData) => { const body = JSON.stringify(payload); try { - const url = new URL(`${keyServer}/roles`); + const url = new URL(`${apiBaseUrl}/roles`); const response = await fetch(url.toString(), { method: "POST", headers: { @@ -143,7 +140,6 @@ export const addRole = async (formData: FormData) => { export const updateRole = async (formData: FormData, roleId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const name = formData.get("name") as string; const groups = formData.getAll("groups[]") as string[]; @@ -185,7 +181,7 @@ export const updateRole = async (formData: FormData, roleId: string) => { const body = JSON.stringify(payload); try { - const url = new URL(`${keyServer}/roles/${roleId}`); + const url = new URL(`${apiBaseUrl}/roles/${roleId}`); const response = await fetch(url.toString(), { method: "PATCH", headers: { @@ -210,9 +206,8 @@ export const updateRole = async (formData: FormData, roleId: string) => { export const deleteRole = async (roleId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/roles/${roleId}`); + const url = new URL(`${apiBaseUrl}/roles/${roleId}`); try { const response = await fetch(url.toString(), { method: "DELETE", diff --git a/ui/actions/scans/scans.ts b/ui/actions/scans/scans.ts index 954b600a26..d647c3fdfb 100644 --- a/ui/actions/scans/scans.ts +++ b/ui/actions/scans/scans.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; export const getScans = async ({ page = 1, @@ -16,8 +16,7 @@ export const getScans = async ({ if (isNaN(Number(page)) || page < 1) redirect("/scans"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/scans`); + const url = new URL(`${apiBaseUrl}/scans`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -51,8 +50,7 @@ export const getScans = async ({ export const getScansByState = async () => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/scans`); + const url = new URL(`${apiBaseUrl}/scans`); // Request only the necessary fields to optimize the response url.searchParams.append("fields[scans]", "state"); @@ -87,8 +85,7 @@ export const getScansByState = async () => { export const getScan = async (scanId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/scans/${scanId}`); + const url = new URL(`${apiBaseUrl}/scans/${scanId}`); try { const scan = await fetch(url.toString(), { @@ -110,7 +107,6 @@ export const getScan = async (scanId: string) => { export const scanOnDemand = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerId = formData.get("providerId"); const scanName = formData.get("scanName") || undefined; @@ -119,7 +115,7 @@ export const scanOnDemand = async (formData: FormData) => { return { error: "Provider ID is required" }; } - const url = new URL(`${keyServer}/scans`); + const url = new URL(`${apiBaseUrl}/scans`); try { const requestBody = { @@ -169,11 +165,10 @@ export const scanOnDemand = async (formData: FormData) => { export const scheduleDaily = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const providerId = formData.get("providerId"); - const url = new URL(`${keyServer}/schedules/daily`); + const url = new URL(`${apiBaseUrl}/schedules/daily`); try { const response = await fetch(url.toString(), { @@ -211,12 +206,11 @@ export const scheduleDaily = async (formData: FormData) => { export const updateScan = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const scanId = formData.get("scanId"); const scanName = formData.get("scanName"); - const url = new URL(`${keyServer}/scans/${scanId}`); + const url = new URL(`${apiBaseUrl}/scans/${scanId}`); try { const response = await fetch(url.toString(), { @@ -251,8 +245,7 @@ export const updateScan = async (formData: FormData) => { export const getExportsZip = async (scanId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/scans/${scanId}/report`); + const url = new URL(`${apiBaseUrl}/scans/${scanId}/report`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/services/index.ts b/ui/actions/services/index.ts deleted file mode 100644 index b2221a94a8..0000000000 --- a/ui/actions/services/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./services"; diff --git a/ui/actions/services/services.ts b/ui/actions/services/services.ts deleted file mode 100644 index cfd295e1cb..0000000000 --- a/ui/actions/services/services.ts +++ /dev/null @@ -1,97 +0,0 @@ -"use server"; - -import { revalidatePath } from "next/cache"; - -import { auth } from "@/auth.config"; - -export const getServices = async () => { - const session = await auth(); - - const keyServer = process.env.API_BASE_URL; - const servicesToFetch = [ - { id: "accessanalyzer", alias: "IAM Access Analyzer" }, - { id: "account", alias: "AWS Account" }, - { id: "acm", alias: "AWS Certificate Manager" }, - { id: "apigateway", alias: "Amazon API Gateway" }, - { id: "apigatewayv2", alias: "Amazon API Gateway V2" }, - { id: "athena", alias: "Amazon Athena" }, - { id: "autoscaling", alias: "Amazon EC2 Auto Scaling" }, - { id: "awslambda", alias: "AWS Lambda" }, - { id: "backup", alias: "AWS Backup" }, - { id: "cloudformation", alias: "AWS CloudFormation" }, - { id: "cloudfront", alias: "Amazon CloudFront" }, - { id: "cloudtrail", alias: "AWS CloudTrail" }, - { id: "cloudwatch", alias: "Amazon CloudWatch" }, - { id: "codeartifact", alias: "AWS CodeArtifact" }, - { id: "codebuild", alias: "AWS CodeBuild" }, - { id: "config", alias: "AWS Config" }, - { id: "dlm", alias: "Amazon Data Lifecycle Manager" }, - { id: "drs", alias: "AWS Data Replication Service" }, - { id: "dynamodb", alias: "Amazon DynamoDB" }, - { id: "ec2", alias: "Amazon EC2" }, - { id: "ecr", alias: "Amazon ECR" }, - { id: "ecs", alias: "Amazon ECS" }, - { id: "efs", alias: "Amazon EFS" }, - { id: "eks", alias: "Amazon EKS" }, - { id: "elasticache", alias: "Amazon ElastiCache" }, - { id: "elb", alias: "Elastic Load Balancing" }, - { id: "elbv2", alias: "Elastic Load Balancing v2" }, - { id: "emr", alias: "Amazon EMR" }, - { id: "fms", alias: "AWS Firewall Manager" }, - { id: "glacier", alias: "Amazon Glacier" }, - { id: "glue", alias: "AWS Glue" }, - { id: "guardduty", alias: "Amazon GuardDuty" }, - { id: "iam", alias: "AWS IAM" }, - { id: "inspector2", alias: "Amazon Inspector" }, - { id: "kms", alias: "AWS KMS" }, - { id: "macie", alias: "Amazon Macie" }, - { id: "networkfirewall", alias: "AWS Network Firewall" }, - { id: "organizations", alias: "AWS Organizations" }, - { id: "rds", alias: "Amazon RDS" }, - { id: "resourceexplorer2", alias: "AWS Resource Groups" }, - { id: "route53", alias: "Amazon Route 53" }, - { id: "s3", alias: "Amazon S3" }, - { id: "secretsmanager", alias: "AWS Secrets Manager" }, - { id: "securityhub", alias: "AWS Security Hub" }, - { id: "sns", alias: "Amazon SNS" }, - { id: "sqs", alias: "Amazon SQS" }, - { id: "ssm", alias: "AWS Systems Manager" }, - { id: "ssmincidents", alias: "AWS Systems Manager Incident Manager" }, - { id: "trustedadvisor", alias: "AWS Trusted Advisor" }, - { id: "vpc", alias: "Amazon VPC" }, - { id: "wafv2", alias: "AWS WAF" }, - { id: "wellarchitected", alias: "AWS Well-Architected Tool" }, - ]; - - const parsedData = []; - - for (const service of servicesToFetch) { - const url = new URL(`${keyServer}/findings`); - url.searchParams.append("filter[service]", service.id); - url.searchParams.append("filter[status]", "FAIL"); - - try { - const response = await fetch(url.toString(), { - headers: { - Accept: "application/vnd.api+json", - Authorization: `Bearer ${session?.accessToken}`, - }, - }); - - const data = await response.json(); - const failFindings = data.meta.pagination.count; - - parsedData.push({ - service_id: service.id, - service_alias: service.alias, - fail_findings: failFindings, - }); - } catch (error) { - // eslint-disable-next-line no-console - console.error(`Error fetching data for service ${service.id}:`, error); - } - } - - revalidatePath("/services"); - return parsedData; -}; diff --git a/ui/actions/task/tasks.ts b/ui/actions/task/tasks.ts index fdf75c7cea..dc4ea9eee9 100644 --- a/ui/actions/task/tasks.ts +++ b/ui/actions/task/tasks.ts @@ -1,13 +1,12 @@ "use server"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; export const getTask = async (taskId: string) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/tasks/${taskId}`); + const url = new URL(`${apiBaseUrl}/tasks/${taskId}`); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/users/users.ts b/ui/actions/users/users.ts index 4e64023b13..18db0ab2ec 100644 --- a/ui/actions/users/users.ts +++ b/ui/actions/users/users.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { auth } from "@/auth.config"; -import { getErrorMessage, parseStringify } from "@/lib"; +import { apiBaseUrl, getErrorMessage, parseStringify } from "@/lib"; export const getUsers = async ({ page = 1, @@ -16,8 +16,7 @@ export const getUsers = async ({ if (isNaN(Number(page)) || page < 1) redirect("/users?include=roles"); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/users?include=roles`); + const url = new URL(`${apiBaseUrl}/users?include=roles`); if (page) url.searchParams.append("page[number]", page.toString()); if (query) url.searchParams.append("filter[search]", query); @@ -50,7 +49,6 @@ export const getUsers = async ({ export const updateUser = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const userId = formData.get("userId") as string; // Ensure userId is a string const userName = formData.get("name") as string | null; @@ -58,7 +56,7 @@ export const updateUser = async (formData: FormData) => { const userEmail = formData.get("email") as string | null; const userCompanyName = formData.get("company_name") as string | null; - const url = new URL(`${keyServer}/users/${userId}`); + const url = new URL(`${apiBaseUrl}/users/${userId}`); // Prepare attributes to send based on changes const attributes: Record = {}; @@ -105,7 +103,6 @@ export const updateUser = async (formData: FormData) => { export const updateUserRole = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const userId = formData.get("userId") as string; const roleId = formData.get("roleId") as string; @@ -115,7 +112,7 @@ export const updateUserRole = async (formData: FormData) => { return { error: "userId and roleId are required" }; } - const url = new URL(`${keyServer}/users/${userId}/relationships/roles`); + const url = new URL(`${apiBaseUrl}/users/${userId}/relationships/roles`); const requestBody = { data: [ @@ -156,14 +153,13 @@ export const updateUserRole = async (formData: FormData) => { export const deleteUser = async (formData: FormData) => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; const userId = formData.get("userId"); if (!userId) { return { error: "User ID is required" }; } - const url = new URL(`${keyServer}/users/${userId}`); + const url = new URL(`${apiBaseUrl}/users/${userId}`); try { const response = await fetch(url.toString(), { @@ -197,8 +193,7 @@ export const deleteUser = async (formData: FormData) => { export const getProfileInfo = async () => { const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/users/me`); + const url = new URL(`${apiBaseUrl}/users/me`); try { const response = await fetch(url.toString(), { diff --git a/ui/app/(prowler)/services/page.tsx b/ui/app/(prowler)/services/page.tsx index 5177ea2310..dc4878cf64 100644 --- a/ui/app/(prowler)/services/page.tsx +++ b/ui/app/(prowler)/services/page.tsx @@ -1,18 +1,10 @@ import { Spacer } from "@nextui-org/react"; -import { Suspense } from "react"; -import { getServices } from "@/actions/services"; import { FilterControls } from "@/components/filters"; -import { ServiceCard, ServiceSkeletonGrid } from "@/components/services"; import { ContentLayout } from "@/components/ui"; -import { SearchParamsProps } from "@/types"; -export default async function Services({ - searchParams, -}: { - searchParams: SearchParamsProps; -}) { - const searchParamsKey = JSON.stringify(searchParams || {}); +export default async function Services() { + // const searchParamsKey = JSON.stringify(searchParams || {}); return ( - }> + {/* }> - + */} ); } - -const SSRServiceGrid = async () => { - const services = await getServices(); - - return ( -
- {services?.map((service: any) => ( - - ))} -
- ); -}; diff --git a/ui/app/api/auth/callback/github/route.ts b/ui/app/api/auth/callback/github/route.ts index 918d019360..2c70a8cd88 100644 --- a/ui/app/api/auth/callback/github/route.ts +++ b/ui/app/api/auth/callback/github/route.ts @@ -3,13 +3,11 @@ import { NextResponse } from "next/server"; import { signIn } from "@/auth.config"; -import { baseUrl } from "@/lib/helper"; +import { apiBaseUrl, baseUrl } from "@/lib/helper"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); - const keyServer = process.env.API_BASE_URL; - const code = searchParams.get("code"); const params = new URLSearchParams(); @@ -23,7 +21,7 @@ export async function GET(req: Request) { } try { - const response = await fetch(`${keyServer}/tokens/github`, { + const response = await fetch(`${apiBaseUrl}/tokens/github`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", diff --git a/ui/app/api/auth/callback/google/route.ts b/ui/app/api/auth/callback/google/route.ts index 521ed1c413..0f92d8ef46 100644 --- a/ui/app/api/auth/callback/google/route.ts +++ b/ui/app/api/auth/callback/google/route.ts @@ -3,13 +3,11 @@ import { NextResponse } from "next/server"; import { signIn } from "@/auth.config"; -import { baseUrl } from "@/lib/helper"; +import { apiBaseUrl, baseUrl } from "@/lib/helper"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); - const keyServer = process.env.API_BASE_URL; - const code = searchParams.get("code"); const params = new URLSearchParams(); @@ -23,7 +21,7 @@ export async function GET(req: Request) { } try { - const response = await fetch(`${keyServer}/tokens/google`, { + const response = await fetch(`${apiBaseUrl}/tokens/google`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", diff --git a/ui/auth.config.ts b/ui/auth.config.ts index 6db01ce49a..ed15ed4a38 100644 --- a/ui/auth.config.ts +++ b/ui/auth.config.ts @@ -4,6 +4,7 @@ import Credentials from "next-auth/providers/credentials"; import { z } from "zod"; import { getToken, getUserByMe } from "./actions/auth"; +import { apiBaseUrl } from "./lib"; interface CustomJwtPayload extends JwtPayload { user_id: string; @@ -11,8 +12,7 @@ interface CustomJwtPayload extends JwtPayload { } const refreshAccessToken = async (token: JwtPayload) => { - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/tokens/refresh`); + const url = new URL(`${apiBaseUrl}/tokens/refresh`); const bodyData = { data: { diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index 428270ed2e..7f7e199fba 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -2,6 +2,7 @@ import { getTask } from "@/actions/task"; import { AuthSocialProvider, MetaDataProps, PermissionInfo } from "@/types"; export const baseUrl = process.env.AUTH_URL || "http://localhost:3000"; +export const apiBaseUrl = process.env.API_BASE_URL; export const getAuthUrl = (provider: AuthSocialProvider) => { const config = { From bb149a30a757ad42e32b59e328959bcd0bc45f30 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:31:47 +0100 Subject: [PATCH 022/359] fix(microsoft365): typo `Microsoft365NotTenantIdButClientIdAndClienSecretError` (#7244) --- prowler/providers/microsoft365/exceptions/exceptions.py | 4 ++-- prowler/providers/microsoft365/microsoft365_provider.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/prowler/providers/microsoft365/exceptions/exceptions.py b/prowler/providers/microsoft365/exceptions/exceptions.py index b1da4f1fbc..45c645802d 100644 --- a/prowler/providers/microsoft365/exceptions/exceptions.py +++ b/prowler/providers/microsoft365/exceptions/exceptions.py @@ -90,7 +90,7 @@ class Microsoft365BaseException(ProwlerException): "message": "Microsoft365 tenant ID error: browser authentication flag (--browser-auth) not found", "remediation": "To use browser authentication, ensure the tenant ID is properly set.", }, - (6021, "Microsoft365NotTenantIdButClientIdAndClienSecretError"): { + (6021, "Microsoft365NotTenantIdButClientIdAndClientSecretError"): { "message": "Tenant Id is required for Microsoft365 static credentials. Make sure you are using the correct credentials.", "remediation": "Check the Microsoft365 Tenant ID and ensure it is properly set up.", }, @@ -270,7 +270,7 @@ class Microsoft365BrowserAuthNoFlagError(Microsoft365CredentialsError): ) -class Microsoft365NotTenantIdButClientIdAndClienSecretError( +class Microsoft365NotTenantIdButClientIdAndClientSecretError( Microsoft365CredentialsError ): def __init__(self, file=None, original_exception=None, message=None): diff --git a/prowler/providers/microsoft365/microsoft365_provider.py b/prowler/providers/microsoft365/microsoft365_provider.py index af7a723f67..668381d576 100644 --- a/prowler/providers/microsoft365/microsoft365_provider.py +++ b/prowler/providers/microsoft365/microsoft365_provider.py @@ -40,7 +40,7 @@ from prowler.providers.microsoft365.exceptions.exceptions import ( Microsoft365InteractiveBrowserCredentialError, Microsoft365InvalidProviderIdError, Microsoft365NoAuthenticationMethodError, - Microsoft365NotTenantIdButClientIdAndClienSecretError, + Microsoft365NotTenantIdButClientIdAndClientSecretError, Microsoft365NotValidClientIdError, Microsoft365NotValidClientSecretError, Microsoft365NotValidTenantIdError, @@ -281,7 +281,7 @@ class Microsoft365Provider(Provider): ) else: if not tenant_id: - raise Microsoft365NotTenantIdButClientIdAndClienSecretError( + raise Microsoft365NotTenantIdButClientIdAndClientSecretError( file=os.path.basename(__file__), message="Tenant Id is required for Microsoft365 static credentials. Make sure you are using the correct credentials.", ) From b09e83b17198edf659ae1759e168da980305540a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?= Date: Tue, 18 Mar 2025 10:09:13 +0100 Subject: [PATCH 023/359] chore: add api reference to download report section (#7243) --- docs/tutorials/prowler-app.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/tutorials/prowler-app.md b/docs/tutorials/prowler-app.md index 18e5f5a2df..6228836fcf 100644 --- a/docs/tutorials/prowler-app.md +++ b/docs/tutorials/prowler-app.md @@ -184,3 +184,6 @@ To download these files, click the **Download** button. This button becomes avai This action downloads a `zip` file containing an `output` folder, which includes the files mentioned above: CSV, JSON-OSCF, and HTML reports. Output folder + +???+ note "API Note" + To learn more about the API endpoint the UI uses to download ZIP exports, see: [Prowler API Reference - Download Scan Output](https://api.prowler.com/api/v1/docs#tag/Scan/operation/scans_report_retrieve) From eb7c16aba5859225c13ab0172aba2c220a5596c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Mar 2025 11:06:46 +0100 Subject: [PATCH 024/359] chore(deps): bump azure-mgmt-storage from 21.2.1 to 22.1.1 (#7098) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 9 +++++---- pyproject.toml | 2 +- ..._default_network_access_rule_is_denied_test.py | 15 ++++++++++----- ...vices_are_trusted_to_access_is_enabled_test.py | 15 ++++++++++----- ..._private_endpoints_in_storage_accounts_test.py | 15 +++++++++++---- .../storage_ensure_soft_delete_is_enabled_test.py | 11 +++++++---- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/poetry.lock b/poetry.lock index 628d7efb46..b427a19e46 100644 --- a/poetry.lock +++ b/poetry.lock @@ -631,20 +631,21 @@ msrest = ">=0.6.21" [[package]] name = "azure-mgmt-storage" -version = "21.2.1" +version = "22.1.1" description = "Microsoft Azure Storage Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-storage-21.2.1.tar.gz", hash = "sha256:503a7ff9c31254092b0656445f5728bfdfda2d09d46a82e97019eaa9a1ecec64"}, - {file = "azure_mgmt_storage-21.2.1-py3-none-any.whl", hash = "sha256:f97df1fa39cde9dbacf2cd96c9cba1fc196932185e24853e276f74b18a0bd031"}, + {file = "azure_mgmt_storage-22.1.1-py3-none-any.whl", hash = "sha256:a4a4064918dcfa4f1cbebada5bf064935d66f2a3647a2f46a1f1c9348736f5d9"}, + {file = "azure_mgmt_storage-22.1.1.tar.gz", hash = "sha256:25aaa5ae8c40c30e2f91f8aae6f52906b0557e947d5c1b9817d4ff9decc11340"}, ] [package.dependencies] azure-common = ">=1.1" azure-mgmt-core = ">=1.3.2" isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-subscription" @@ -5335,4 +5336,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "29ed097b3f41c777e0b28202291f80e0c7f932eb44b4d2ad3ef7dd8999ff42c6" +content-hash = "4887e227b68e8bbc97bb67df42ae2804563607856ca18b78a2b198282d50a6e7" diff --git a/pyproject.toml b/pyproject.toml index 44ce5b58af..6119305eba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "azure-mgmt-search==9.1.0", "azure-mgmt-security==7.0.0", "azure-mgmt-sql==3.0.1", - "azure-mgmt-storage==21.2.1", + "azure-mgmt-storage==22.1.1", "azure-mgmt-subscription==3.1.1", "azure-mgmt-web==8.0.0", "azure-storage-blob==12.24.1", diff --git a/tests/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied_test.py b/tests/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied_test.py index ad80b1e80a..9ed07a4644 100644 --- a/tests/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied_test.py +++ b/tests/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied_test.py @@ -1,9 +1,10 @@ from unittest import mock from uuid import uuid4 -from azure.mgmt.storage.v2022_09_01.models import NetworkRuleSet - -from prowler.providers.azure.services.storage.storage_service import Account +from prowler.providers.azure.services.storage.storage_service import ( + Account, + NetworkRuleSet, +) from tests.providers.azure.azure_fixtures import ( AZURE_SUBSCRIPTION_ID, set_mocked_azure_provider, @@ -46,7 +47,9 @@ class Test_storage_default_network_access_rule_is_denied: enable_https_traffic_only=False, infrastructure_encryption=False, allow_blob_public_access=None, - network_rule_set=NetworkRuleSet(default_action="Allow"), + network_rule_set=NetworkRuleSet( + default_action="Allow", bypass="AzureServices" + ), encryption_type=None, minimum_tls_version=None, key_expiration_period_in_days=None, @@ -96,7 +99,9 @@ class Test_storage_default_network_access_rule_is_denied: enable_https_traffic_only=False, infrastructure_encryption=False, allow_blob_public_access=None, - network_rule_set=NetworkRuleSet(default_action="Deny"), + network_rule_set=NetworkRuleSet( + default_action="Deny", bypass="AzureServices" + ), encryption_type=None, minimum_tls_version=None, key_expiration_period_in_days=None, diff --git a/tests/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled_test.py b/tests/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled_test.py index 7b2780eb89..7d8eb1b741 100644 --- a/tests/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled_test.py +++ b/tests/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled_test.py @@ -1,9 +1,10 @@ from unittest import mock from uuid import uuid4 -from azure.mgmt.storage.v2022_09_01.models import NetworkRuleSet - -from prowler.providers.azure.services.storage.storage_service import Account +from prowler.providers.azure.services.storage.storage_service import ( + Account, + NetworkRuleSet, +) from tests.providers.azure.azure_fixtures import ( AZURE_SUBSCRIPTION_ID, set_mocked_azure_provider, @@ -46,7 +47,9 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled: enable_https_traffic_only=False, infrastructure_encryption=False, allow_blob_public_access=None, - network_rule_set=NetworkRuleSet(bypass=[None]), + network_rule_set=NetworkRuleSet( + bypass="None", default_action="Deny" + ), encryption_type=None, minimum_tls_version=None, key_expiration_period_in_days=None, @@ -96,7 +99,9 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled: enable_https_traffic_only=False, infrastructure_encryption=False, allow_blob_public_access=None, - network_rule_set=NetworkRuleSet(bypass=["AzureServices"]), + network_rule_set=NetworkRuleSet( + bypass="AzureServices", default_action="Allow" + ), encryption_type=None, minimum_tls_version=None, key_expiration_period_in_days=None, diff --git a/tests/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts_test.py b/tests/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts_test.py index a446cb2d57..50f7dfc2d2 100644 --- a/tests/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts_test.py +++ b/tests/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts_test.py @@ -1,9 +1,10 @@ from unittest import mock from uuid import uuid4 -from azure.mgmt.storage.v2023_01_01.models import PrivateEndpointConnection - -from prowler.providers.azure.services.storage.storage_service import Account +from prowler.providers.azure.services.storage.storage_service import ( + Account, + PrivateEndpointConnection, +) from tests.providers.azure.azure_fixtures import ( AZURE_SUBSCRIPTION_ID, set_mocked_azure_provider, @@ -105,7 +106,13 @@ class Test_storage_ensure_private_endpoints_in_storage_accounts: minimum_tls_version=None, key_expiration_period_in_days=None, location="westeurope", - private_endpoint_connections=PrivateEndpointConnection(), + private_endpoint_connections=PrivateEndpointConnection( + id=str( + uuid4(), + ), + name="Test Private Endpoint Connection", + type="Test Type", + ), ) ] } diff --git a/tests/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled_test.py b/tests/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled_test.py index 6992a523c9..3bac97b5b5 100644 --- a/tests/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled_test.py +++ b/tests/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled_test.py @@ -1,11 +1,10 @@ from unittest import mock from uuid import uuid4 -from azure.mgmt.storage.v2023_01_01.models import DeleteRetentionPolicy - from prowler.providers.azure.services.storage.storage_service import ( Account, BlobProperties, + DeleteRetentionPolicy, ) from tests.providers.azure.azure_fixtures import ( AZURE_SUBSCRIPTION_ID, @@ -90,7 +89,9 @@ class Test_storage_ensure_soft_delete_is_enabled: name=None, type=None, default_service_version=None, - container_delete_retention_policy=DeleteRetentionPolicy(enabled=False), + container_delete_retention_policy=DeleteRetentionPolicy( + enabled=False, days=7 + ), ) storage_client.storage_accounts = { AZURE_SUBSCRIPTION_ID: [ @@ -150,7 +151,9 @@ class Test_storage_ensure_soft_delete_is_enabled: name=None, type=None, default_service_version=None, - container_delete_retention_policy=DeleteRetentionPolicy(enabled=True), + container_delete_retention_policy=DeleteRetentionPolicy( + enabled=True, days=7 + ), ) storage_client.storage_accounts = { AZURE_SUBSCRIPTION_ID: [ From 7c4571b55e19dc524bf4986067357c9aef87cf59 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 18 Mar 2025 12:05:38 +0100 Subject: [PATCH 025/359] feat(providers): add component to render a link to the documentation (#7282) --- .../workflow/forms/connect-account-form.tsx | 17 +---- .../forms/update-via-credentials-form.tsx | 15 ++--- .../workflow/forms/via-credentials-form.tsx | 15 ++--- .../via-credentials/aws-credentials-form.tsx | 6 +- .../azure-credentials-form.tsx | 6 +- .../via-credentials/gcp-credentials-form.tsx | 6 +- .../via-credentials/k8s-credentials-form.tsx | 6 +- .../workflow/forms/via-role/aws-role-form.tsx | 6 +- ui/components/providers/workflow/index.ts | 1 + .../workflow/provider-title-docs.tsx | 66 +++++++++++++++++++ 10 files changed, 95 insertions(+), 49 deletions(-) create mode 100644 ui/components/providers/workflow/provider-title-docs.tsx diff --git a/ui/components/providers/workflow/forms/connect-account-form.tsx b/ui/components/providers/workflow/forms/connect-account-form.tsx index 5866189627..597943ae36 100644 --- a/ui/components/providers/workflow/forms/connect-account-form.tsx +++ b/ui/components/providers/workflow/forms/connect-account-form.tsx @@ -9,17 +9,13 @@ import * as z from "zod"; import { useToast } from "@/components/ui"; import { CustomButton, CustomInput } from "@/components/ui/custom"; -import { - getProviderLogo, - getProviderName, - ProviderType, -} from "@/components/ui/entities"; +import { ProviderType } from "@/components/ui/entities"; import { Form } from "@/components/ui/form"; import { addProvider } from "../../../../actions/providers/providers"; import { addProviderFormSchema, ApiError } from "../../../../types"; import { RadioGroupProvider } from "../../radio-group-provider"; - +import { ProviderTitleDocs } from "../provider-title-docs"; export type FormValues = z.infer; // Helper function for labels and placeholders @@ -170,14 +166,7 @@ export const ConnectAccountForm = () => { {/* Step 2: UID, alias, and credentials (if AWS) */} {prevStep === 2 && ( <> -
- {providerType && getProviderLogo(providerType as ProviderType)} - - {providerType - ? getProviderName(providerType as ProviderType) - : "Unknown Provider"} - -
+ -
- {providerType && getProviderLogo(providerType as ProviderType)} - - {providerType - ? getProviderName(providerType as ProviderType) - : "Unknown Provider"} - -
+ + + {providerType === "aws" && ( -
- {providerType && getProviderLogo(providerType as ProviderType)} - - {providerType - ? getProviderName(providerType as ProviderType) - : "Unknown Provider"} - -
+ + + {providerType === "aws" && ( { return ( <> -
-
+
+
Connect via Credentials
-
+
Please provide the information for your AWS credentials.
diff --git a/ui/components/providers/workflow/forms/via-credentials/azure-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/azure-credentials-form.tsx index b78642b8d2..47a9bb6fa4 100644 --- a/ui/components/providers/workflow/forms/via-credentials/azure-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials/azure-credentials-form.tsx @@ -10,11 +10,11 @@ export const AzureCredentialsForm = ({ }) => { return ( <> -
-
+
+
Connect via Credentials
-
+
Please provide the information for your Azure credentials.
diff --git a/ui/components/providers/workflow/forms/via-credentials/gcp-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/gcp-credentials-form.tsx index 784f173f49..3e3ecefb6b 100644 --- a/ui/components/providers/workflow/forms/via-credentials/gcp-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials/gcp-credentials-form.tsx @@ -10,11 +10,11 @@ export const GCPcredentialsForm = ({ }) => { return ( <> -
-
+
+
Connect via Credentials
-
+
Please provide the information for your GCP credentials.
diff --git a/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx index 3e6caeca88..f589afb8f4 100644 --- a/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx @@ -10,11 +10,11 @@ export const KubernetesCredentialsForm = ({ }) => { return ( <> -
-
+
+
Connect via Credentials
-
+
Please provide the kubeconfig content for your Kubernetes credentials.
diff --git a/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx b/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx index 318c463958..7ed4cd9438 100644 --- a/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx +++ b/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx @@ -23,11 +23,11 @@ export const AWSCredentialsRoleForm = ({ return ( <> -
-
+
+
Connect assuming IAM Role
-
+
Please provide the information for your AWS credentials.
diff --git a/ui/components/providers/workflow/index.ts b/ui/components/providers/workflow/index.ts index 6c7387eafb..65cabc53ce 100644 --- a/ui/components/providers/workflow/index.ts +++ b/ui/components/providers/workflow/index.ts @@ -1,4 +1,5 @@ export * from "./credentials-role-helper"; +export * from "./provider-title-docs"; export * from "./skeleton-provider-workflow"; export * from "./vertical-steps"; export * from "./workflow-add-provider"; diff --git a/ui/components/providers/workflow/provider-title-docs.tsx b/ui/components/providers/workflow/provider-title-docs.tsx new file mode 100644 index 0000000000..2abede0347 --- /dev/null +++ b/ui/components/providers/workflow/provider-title-docs.tsx @@ -0,0 +1,66 @@ +import Link from "next/link"; + +import { getProviderName } from "@/components/ui/entities/get-provider-logo"; +import { ProviderType } from "@/components/ui/entities/get-provider-logo"; +import { getProviderLogo } from "@/components/ui/entities/get-provider-logo"; + +export const ProviderTitleDocs = ({ + providerType, +}: { + providerType: ProviderType; +}) => { + const getProviderHelpText = (provider: string) => { + switch (provider) { + case "aws": + return { + text: "Need help connecting your AWS account?", + link: "https://goto.prowler.com/provider-aws", + }; + case "azure": + return { + text: "Need help connecting your Azure subscription?", + link: "https://goto.prowler.com/provider-azure", + }; + case "gcp": + return { + text: "Need help connecting your GCP project?", + link: "https://goto.prowler.com/provider-gcp", + }; + case "kubernetes": + return { + text: "Need help connecting your Kubernetes cluster?", + link: "https://goto.prowler.com/provider-k8s", + }; + default: + return { + text: "How to setup a provider?", + link: "https://goto.prowler.com/provider-help", + }; + } + }; + + return ( +
+
+ {providerType && getProviderLogo(providerType as ProviderType)} + + {providerType + ? getProviderName(providerType as ProviderType) + : "Unknown Provider"} + +
+
+

+ {getProviderHelpText(providerType as string).text} +

+ + Read the docs + +
+
+ ); +}; From 447bf832cd4df33e15e5b2b85d0bf48b4603dce0 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Tue, 18 Mar 2025 12:50:44 +0100 Subject: [PATCH 026/359] chore(regions_update): Changes in regions for AWS services (#7281) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 1 + 1 file changed, 1 insertion(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index f020c6f038..facd5ed464 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -6412,6 +6412,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 7053b2bb37554e712245af417cb5611174bb19b3 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 18 Mar 2025 13:43:46 +0100 Subject: [PATCH 027/359] chore: add env vars for social login (#7257) 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 --- .env | 9 +++++++++ ui/lib/helper.ts | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.env b/.env index 23d6f30721..82ba476870 100644 --- a/.env +++ b/.env @@ -124,3 +124,12 @@ SENTRY_RELEASE=local #### Prowler release version #### NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.5.0 + +# Social login credentials +SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google" +SOCIAL_GOOGLE_OAUTH_CLIENT_ID="" +SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET="" + +SOCIAL_GITHUB_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/github" +SOCIAL_GITHUB_OAUTH_CLIENT_ID="" +SOCIAL_GITHUB_OAUTH_CLIENT_SECRET="" diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index 7f7e199fba..b0eaef6221 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -38,12 +38,12 @@ export const getAuthUrl = (provider: AuthSocialProvider) => { }; export const isGoogleOAuthEnabled = - process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_ID !== "" && - process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET !== ""; + !!process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_ID && + !!process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET; export const isGithubOAuthEnabled = - process.env.SOCIAL_GITHUB_OAUTH_CLIENT_ID !== "" && - process.env.SOCIAL_GITHUB_OAUTH_CLIENT_SECRET !== ""; + !!process.env.SOCIAL_GITHUB_OAUTH_CLIENT_ID && + !!process.env.SOCIAL_GITHUB_OAUTH_CLIENT_SECRET; export async function checkTaskStatus( taskId: string, From c8be8dbd9a2c4c609cd6a5e4b8862078629c96c3 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 18 Mar 2025 20:27:19 +0545 Subject: [PATCH 028/359] fix(aws-regions): Use @prowler-bot as author (#7285) --- .github/workflows/sdk-refresh-aws-services-regions.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index 71e8aac4b0..20b7439019 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -52,6 +52,7 @@ jobs: - name: Create Pull Request uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: + author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} commit-message: "feat(regions_update): Update regions for AWS services" branch: "aws-services-regions-updated-${{ github.sha }}" From 802c786ac253342bd53697fd0ea5c91f3041d199 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 18 Mar 2025 21:34:36 +0545 Subject: [PATCH 029/359] fix(test-connection): Handle provider without secret (#7283) --- api/src/backend/api/tests/test_utils.py | 41 ++++++++++++++++--------- api/src/backend/api/utils.py | 5 ++- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/api/src/backend/api/tests/test_utils.py b/api/src/backend/api/tests/test_utils.py index bfeec54852..02a97249c6 100644 --- a/api/src/backend/api/tests/test_utils.py +++ b/api/src/backend/api/tests/test_utils.py @@ -1,25 +1,24 @@ from datetime import datetime, timedelta, timezone -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch import pytest +from rest_framework.exceptions import NotFound, ValidationError + +from api.db_router import MainRouter +from api.exceptions import InvitationTokenExpiredException +from api.models import Invitation, Provider +from api.utils import ( + get_prowler_provider_kwargs, + initialize_prowler_provider, + merge_dicts, + prowler_provider_connection_test, + return_prowler_provider, + validate_invitation, +) from prowler.providers.aws.aws_provider import AwsProvider from prowler.providers.azure.azure_provider import AzureProvider from prowler.providers.gcp.gcp_provider import GcpProvider from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider -from rest_framework.exceptions import ValidationError, NotFound - -from api.db_router import MainRouter -from api.exceptions import InvitationTokenExpiredException -from api.models import Invitation -from api.models import Provider -from api.utils import ( - merge_dicts, - return_prowler_provider, - initialize_prowler_provider, - prowler_provider_connection_test, - get_prowler_provider_kwargs, -) -from api.utils import validate_invitation class TestMergeDicts: @@ -144,6 +143,18 @@ class TestProwlerProviderConnectionTest: key="value", provider_id="1234567890", raise_on_exception=False ) + @pytest.mark.django_db + @patch("api.utils.return_prowler_provider") + def test_prowler_provider_connection_test_without_secret( + self, mock_return_prowler_provider, providers_fixture + ): + mock_return_prowler_provider.return_value = MagicMock() + connection = prowler_provider_connection_test(providers_fixture[0]) + + assert connection.is_connected is False + assert isinstance(connection.error, Provider.secret.RelatedObjectDoesNotExist) + assert str(connection.error) == "Provider has no secret." + class TestGetProwlerProviderKwargs: @pytest.mark.parametrize( diff --git a/api/src/backend/api/utils.py b/api/src/backend/api/utils.py index 9dd86daeaf..31d009dba5 100644 --- a/api/src/backend/api/utils.py +++ b/api/src/backend/api/utils.py @@ -130,7 +130,10 @@ def prowler_provider_connection_test(provider: Provider) -> Connection: Connection: A connection object representing the result of the connection test for the specified provider. """ prowler_provider = return_prowler_provider(provider) - prowler_provider_kwargs = provider.secret.secret + try: + prowler_provider_kwargs = provider.secret.secret + except Provider.secret.RelatedObjectDoesNotExist as secret_error: + return Connection(is_connected=False, error=secret_error) return prowler_provider.test_connection( **prowler_provider_kwargs, provider_id=provider.uid, raise_on_exception=False ) From 9d6147a037e9443ebcb89cfe19928422b9c3971c Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:54:49 +0100 Subject: [PATCH 030/359] fix(route53): solve false positive in `route53_public_hosted_zones_cloudwatch_logging_enabled` (#7201) --- .../aws/services/route53/route53_service.py | 13 ++-- ...d_zones_cloudwatch_logging_enabled_test.py | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/prowler/providers/aws/services/route53/route53_service.py b/prowler/providers/aws/services/route53/route53_service.py index 2c6a2cd786..4cc744c985 100644 --- a/prowler/providers/aws/services/route53/route53_service.py +++ b/prowler/providers/aws/services/route53/route53_service.py @@ -86,13 +86,14 @@ class Route53(AWSService): ) for page in list_query_logging_configs_paginator.paginate(): for logging_config in page["QueryLoggingConfigs"]: - self.hosted_zones[hosted_zone.id].logging_config = ( - LoggingConfig( - cloudwatch_log_group_arn=logging_config[ - "CloudWatchLogsLogGroupArn" - ] + if logging_config["HostedZoneId"] == hosted_zone.id: + self.hosted_zones[hosted_zone.id].logging_config = ( + LoggingConfig( + cloudwatch_log_group_arn=logging_config[ + "CloudWatchLogsLogGroupArn" + ] + ) ) - ) except Exception as error: logger.error( diff --git a/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py b/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py index a5fd5f17c9..7bfc89cae0 100644 --- a/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py +++ b/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py @@ -117,6 +117,65 @@ class Test_route53_public_hosted_zones_cloudwatch_logging_enabled: == f"Route53 Public Hosted Zone {hosted_zone_id} has query logging disabled." ) + def test_two_hosted_zone_public_one_logging_enabled_other_disabled(self): + route53 = mock.MagicMock + hosted_zone_name = "test-domain.com" + hosted_zone_id = "ABCDEF12345678" + log_group_name = "test-log-group" + log_group_arn = f"rn:aws:logs:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:log-group:{log_group_name}" + + hosted_zone_name_disabled = "test-domain-disabled.com" + hosted_zone_id_disabled = "ABCDEF123456789" + + route53.hosted_zones = { + hosted_zone_name: HostedZone( + name=hosted_zone_name, + arn=f"arn:aws:route53:::{hosted_zone_id}", + id=hosted_zone_id, + private_zone=False, + region=AWS_REGION_US_EAST_1, + logging_config=LoggingConfig(cloudwatch_log_group_arn=log_group_arn), + ), + hosted_zone_name_disabled: HostedZone( + name=hosted_zone_name_disabled, + arn=f"arn:aws:route53:::{hosted_zone_id_disabled}", + id=hosted_zone_id_disabled, + private_zone=False, + region=AWS_REGION_US_EAST_1, + ), + } + + with mock.patch( + "prowler.providers.aws.services.route53.route53_service.Route53", + new=route53, + ), mock.patch( + "prowler.providers.aws.services.route53.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_client", + new=route53, + ): + # Test Check + from prowler.providers.aws.services.route53.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_public_hosted_zones_cloudwatch_logging_enabled import ( + route53_public_hosted_zones_cloudwatch_logging_enabled, + ) + + check = route53_public_hosted_zones_cloudwatch_logging_enabled() + result = check.execute() + + assert len(result) == 2 + assert result[0].resource_id == hosted_zone_id + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Route53 Public Hosted Zone {hosted_zone_id} has query logging enabled in Log Group {log_group_arn}." + ) + assert result[1].resource_id == hosted_zone_id_disabled + assert result[1].region == AWS_REGION_US_EAST_1 + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == f"Route53 Public Hosted Zone {hosted_zone_id_disabled} has query logging disabled." + ) + def test_hosted_zone__private(self): route53 = mock.MagicMock hosted_zone_name = "test-domain.com" From 638b3ac0cda9e4015c084cf5b78d9defba505aef Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 18 Mar 2025 17:05:56 +0100 Subject: [PATCH 031/359] chore(providers): change wording when adding a new provider (#7280) --- .../workflow/workflow-add-provider.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/components/providers/workflow/workflow-add-provider.tsx b/ui/components/providers/workflow/workflow-add-provider.tsx index abc5c0b78f..edad4beed8 100644 --- a/ui/components/providers/workflow/workflow-add-provider.tsx +++ b/ui/components/providers/workflow/workflow-add-provider.tsx @@ -8,21 +8,21 @@ import { VerticalSteps } from "./vertical-steps"; const steps = [ { - title: "Add your cloud provider", + title: "Choose your Cloud Provider", description: - "Select the cloud provider for the account to connect and specify whether to use an IAM role or credentials for access.", + "Select the cloud provider you wish to connect and specify your preferred authentication method from the supported options.", href: "/providers/connect-account", }, { - title: "Add credentials to your cloud provider", + title: "Enter Authentication Details", description: - "Provide the credentials required to connect to the cloud provider.", + "Provide the necessary credentials to establish a secure connection to your selected cloud provider.", href: "/providers/add-credentials", }, { - title: "Check connection and launch scan", + title: "Verify Connection & Start Scan", description: - "Verify the connection to ensure that the provided credentials are valid for accessing the cloud provider and initiating a scan.", + "Ensure your credentials are correct and start scanning your cloud environment.", href: "/providers/test-connection", }, ]; @@ -39,11 +39,11 @@ export const WorkflowAddProvider = () => { return (

- Add a cloud provider + Add a Cloud Provider

- Complete the steps to configure the cloud provider, enabling the launch - of the first scan once completed. + Complete these steps to configure your cloud provider and initiate your + first scan.

Date: Tue, 18 Mar 2025 17:14:25 +0100 Subject: [PATCH 032/359] chore(deps): bump azure-mgmt-containerservice from 34.0.0 to 34.1.0 (#6989) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index b427a19e46..c2a4055d0f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -441,14 +441,14 @@ isodate = ">=0.6.1,<1.0.0" [[package]] name = "azure-mgmt-containerservice" -version = "34.0.0" +version = "34.1.0" description = "Microsoft Azure Container Service Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_mgmt_containerservice-34.0.0-py3-none-any.whl", hash = "sha256:34be8172241e3c2c444682407970a938f60e3b2bd06304eaae0a1ba641f2262d"}, - {file = "azure_mgmt_containerservice-34.0.0.tar.gz", hash = "sha256:822d07828b746a5ea5408a8b3770f41dc424d6c4c28de53c29611b62bef8aea3"}, + {file = "azure_mgmt_containerservice-34.1.0-py3-none-any.whl", hash = "sha256:1faa1714e0100c6ee4cfb8d2eadb1c270b548a84b0070c74e9fe646056a5cb12"}, + {file = "azure_mgmt_containerservice-34.1.0.tar.gz", hash = "sha256:637a6cf8f06636c016ad151d76f9c7ba75bd05d4334b3dd7837eb8b517f30dbe"}, ] [package.dependencies] @@ -5336,4 +5336,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "4887e227b68e8bbc97bb67df42ae2804563607856ca18b78a2b198282d50a6e7" +content-hash = "0023fa78be2b6e67ca726e0045d7953b2e72b723d8afd80e52b733c11061b66f" diff --git a/pyproject.toml b/pyproject.toml index 6119305eba..c86f541875 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ "azure-mgmt-authorization==4.0.0", "azure-mgmt-compute==34.0.0", "azure-mgmt-containerregistry==10.3.0", - "azure-mgmt-containerservice==34.0.0", + "azure-mgmt-containerservice==34.1.0", "azure-mgmt-cosmosdb==9.7.0", "azure-mgmt-keyvault==10.3.1", "azure-mgmt-monitor==6.0.2", From 64f5a69e84faf2553410e492a8cfb5061d1bf2fe Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 18 Mar 2025 17:22:29 +0100 Subject: [PATCH 033/359] fix: prevent SSR mismatch in OAuth URL generation (#7288) --- ui/app/(auth)/sign-in/page.tsx | 10 +++++++++- ui/components/auth/oss/auth-form.tsx | 9 ++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ui/app/(auth)/sign-in/page.tsx b/ui/app/(auth)/sign-in/page.tsx index cb8b2df43b..c36226e61f 100644 --- a/ui/app/(auth)/sign-in/page.tsx +++ b/ui/app/(auth)/sign-in/page.tsx @@ -1,10 +1,18 @@ import { AuthForm } from "@/components/auth/oss"; -import { isGithubOAuthEnabled, isGoogleOAuthEnabled } from "@/lib/helper"; +import { + getAuthUrl, + isGithubOAuthEnabled, + isGoogleOAuthEnabled, +} from "@/lib/helper"; const SignIn = () => { + const GOOGLE_AUTH_URL = getAuthUrl("google"); + const GITHUB_AUTH_URL = getAuthUrl("github"); return ( diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index 2ab7cefbd2..05e0852ffb 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -18,19 +18,22 @@ import { FormField, FormMessage, } from "@/components/ui/form"; -import { getAuthUrl } from "@/lib/helper"; import { ApiError, authFormSchema } from "@/types"; export const AuthForm = ({ type, invitationToken, isCloudEnv, + googleAuthUrl, + githubAuthUrl, isGoogleOAuthEnabled, isGithubOAuthEnabled, }: { type: string; invitationToken?: string | null; isCloudEnv?: boolean; + googleAuthUrl?: string; + githubAuthUrl?: string; isGoogleOAuthEnabled?: boolean; isGithubOAuthEnabled?: boolean; }) => { @@ -326,7 +329,7 @@ export const AuthForm = ({ variant="bordered" className="w-full" as="a" - href={getAuthUrl("google")} + href={googleAuthUrl} isDisabled={!isGoogleOAuthEnabled} > Continue with Google @@ -364,7 +367,7 @@ export const AuthForm = ({ variant="bordered" className="w-full" as="a" - href={getAuthUrl("github")} + href={githubAuthUrl} isDisabled={!isGithubOAuthEnabled} > Continue with Github From c7956ede6a0fdd2fc57e570647697944ac2565f7 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 18 Mar 2025 22:29:57 +0545 Subject: [PATCH 034/359] chore(security): Add HTTP Security Headers (#7289) --- api/CHANGELOG.md | 1 + api/src/backend/api/tests/test_views.py | 8 ++++++++ api/src/backend/config/django/base.py | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 183f82d495..b645d2085d 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler API** are documented in this file. ### Added - Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167). +- HTTP Security Headers [(#7289)](https://github.com/prowler-cloud/prowler/pull/7289). --- diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 013a22bd12..312ed3f8fc 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -40,6 +40,14 @@ def today_after_n_days(n_days: int) -> str: ) +class TestViewSet: + def test_security_headers(self, client): + response = client.get("/") + assert response.headers["X-Content-Type-Options"] == "nosniff" + assert response.headers["X-Frame-Options"] == "DENY" + assert response.headers["Referrer-Policy"] == "strict-origin-when-cross-origin" + + @pytest.mark.django_db class TestUserViewSet: def test_users_list(self, authenticated_client, create_test_user): diff --git a/api/src/backend/config/django/base.py b/api/src/backend/config/django/base.py index 1afa12ec65..7ce3e8c63c 100644 --- a/api/src/backend/config/django/base.py +++ b/api/src/backend/config/django/base.py @@ -236,3 +236,8 @@ DJANGO_OUTPUT_S3_AWS_SECRET_ACCESS_KEY = env.str( ) DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN = env.str("DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN", "") DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION = env.str("DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION", "") + +# HTTP Security Headers +SECURE_CONTENT_TYPE_NOSNIFF = True +X_FRAME_OPTIONS = "DENY" +SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin" From d75f681c8784246715b5d731bfa117dcda9b0c3e Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 18 Mar 2025 22:34:12 +0545 Subject: [PATCH 035/359] chore(security): Configure HTTP Security Headers (#7220) Co-authored-by: Pablo Lara --- ui/next.config.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ui/next.config.js b/ui/next.config.js index b9f289635e..059659b2f0 100644 --- a/ui/next.config.js +++ b/ui/next.config.js @@ -1,4 +1,39 @@ /** @type {import('next').NextConfig} */ + +// HTTP Security Headers +// 'unsafe-eval' is configured under `script-src` because it is required by NextJS for development mode +const cspHeader = ` + img-src 'self'; + font-src 'self'; + style-src 'self' 'unsafe-inline'; + script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com; + connect-src 'self' https://api.iconify.design https://api.simplesvg.com https://api.unisvg.com https://js.stripe.com; + frame-src 'self' https://js.stripe.com/; + frame-ancestors 'none'; + default-src 'self' +` + module.exports = { output: "standalone", + async headers() { + return [ + { + source: '/(.*)', + headers: [ + { + key: 'Content-Security-Policy', + value: cspHeader.replace(/\n/g, ''), + }, + { + key: 'X-Content-Type-Options', + value: 'nosniff', + }, + { + key: 'Referrer-Policy', + value: 'strict-origin-when-cross-origin', + }, + ], + }, + ] + } }; From 598bdf28bbad478d05b6bd3dff0202f539cb3839 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 12:31:52 +0545 Subject: [PATCH 036/359] chore(deps): bump trufflesecurity/trufflehog from 3.88.17 to 3.88.18 (#7297) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/find-secrets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml index aade5f3ba4..0544906f16 100644 --- a/.github/workflows/find-secrets.yml +++ b/.github/workflows/find-secrets.yml @@ -11,7 +11,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@12164e38f0f1b673ab0594c7d94daf71b0be6823 # v3.88.17 + uses: trufflesecurity/trufflehog@ded5f45b92c00939718787ce586b520bbe795f3b # v3.88.18 with: path: ./ base: ${{ github.event.repository.default_branch }} From 74118f5cfe0f42eb3025942e8f19cdb7d82ce29b Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 19 Mar 2025 13:36:22 +0545 Subject: [PATCH 037/359] chore(social-login): improve copy when not enabled (#7295) --- ui/components/auth/oss/auth-form.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ui/components/auth/oss/auth-form.tsx b/ui/components/auth/oss/auth-form.tsx index 05e0852ffb..375ff7b70b 100644 --- a/ui/components/auth/oss/auth-form.tsx +++ b/ui/components/auth/oss/auth-form.tsx @@ -304,9 +304,8 @@ export const AuthForm = ({
- Google Sign-in is not enabled. Configure the social OAuth - environment variables to enable it. +
+ Social Login with Google is not enabled.{" "} - Github Sign-in is not enabled. Configure the social OAuth - environment variables to enable it. +
+ Social Login with Github is not enabled.{" "} Date: Wed, 19 Mar 2025 09:31:40 +0100 Subject: [PATCH 038/359] fix(k8s): remove typos from PCI 4.0 (#7294) --- .../kubernetes/pci_4.0_kubernetes.json | 7012 +++++++---------- ...d_zones_cloudwatch_logging_enabled_test.py | 15 +- 2 files changed, 3012 insertions(+), 4015 deletions(-) diff --git a/prowler/compliance/kubernetes/pci_4.0_kubernetes.json b/prowler/compliance/kubernetes/pci_4.0_kubernetes.json index f43d582bbe..4dde914458 100644 --- a/prowler/compliance/kubernetes/pci_4.0_kubernetes.json +++ b/prowler/compliance/kubernetes/pci_4.0_kubernetes.json @@ -1,78 +1,78 @@ { "Framework": "PCI", "Version": "4.0", - "Provider": "Kubernetes", + "Provider": "Core", "Description": "The Payment Card Industry Data Security Standard (PCI DSS) is a proprietary information security standard. It's administered by the PCI Security Standards Council, which was founded by American Express, Discover Financial Services, JCB International, MasterCard Worldwide, and Visa Inc. PCI DSS applies to entities that store, process, or transmit cardholder data (CHD) or sensitive authentication data (SAD). This includes, but isn't limited to, merchants, processors, acquirers, issuers, and service providers. The PCI DSS is mandated by the card brands and administered by the Payment Card Industry Security Standards Council.", "Requirements": [ { "Id": "1.2.5.1", "Description": "Checks if Ingress resources in Kubernetes are configured to redirect HTTP traffic to HTTPS. The rule is NON_COMPLIANT if one or more Ingress resources do not have an appropriate redirect annotation configured for HTTP to HTTPS redirection. The rule is also NON_COMPLIANT if one or more Ingress resources are forwarding traffic to another non-secure endpoint instead of redirecting to HTTPS.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "1.2.5.2", "Description": "Checks if Kubernetes Ingress resources are using deprecated SSL protocols for HTTPS communication between Ingress controllers and backend services. This rule is NON_COMPLIANT for an Ingress resource if any 'tls' configuration includes 'SSLv3'.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.3", "Description": "Checks if Kubernetes Ingress resources are configured to enforce a minimum security policy and cipher suite of TLSv1.2 or greater for TLS connections. This rule is NON_COMPLIANT for an Ingress resource if the specified minimum TLS version is below 'TLS1.2'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.4", "Description": "Checks if Kubernetes Ingress resources are using a custom TLS certificate and are configured to use SNI for HTTPS traffic. The rule is NON_COMPLIANT if a custom TLS certificate is associated but the Ingress controller is set up to use a dedicated IP address for SSL termination.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.5", "Description": "Checks if Kubernetes Ingress resources are enforcing HTTPS for traffic to backend services. The rule is NON_COMPLIANT if 'nginx.ingress.kubernetes.io/ssl-redirect' is set to 'false' or if 'nginx.ingress.kubernetes.io/backend-protocol' is 'http' and 'nginx.ingress.kubernetes.io/force-ssl-redirect' is set to 'off'.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.6", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS for HTTP traffic. The rule is NON_COMPLIANT if there are Ingress configurations that allow HTTP traffic without a redirect to HTTPS.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, @@ -91,52 +91,52 @@ { "Id": "1.2.5.8", "Description": "Checks whether your Kubernetes Ingress controllers are using custom SSL policies. The rule is only applicable if there are SSL termination configurations in the Ingress resource.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.9", "Description": "Checks if your Kubernetes Ingress resources use a predefined TLS configuration. The rule is NON_COMPLIANT if the Ingress resource's TLS configuration does not match the specified 'predefinedTLSConfig'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.5.10", "Description": "Checks if your Kubernetes Service of type LoadBalancer is configured with SSL or HTTPS through Ingress or directly with LoadBalancer annotations. The rule is NON_COMPLIANT if there is no SSL or HTTPS configuration present.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "Scheduler", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "Scheduler" } ] }, { "Id": "1.2.5.11", "Description": "Checks if Kubernetes clusters have Pod Security Policies (PSP) enabled. The rule is NON_COMPLIANT if a security context is not defined in the pods or the security context does not satisfy the specified security requirements.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -155,962 +155,962 @@ { "Id": "1.2.5.13", "Description": "Check if Kubernetes cluster nodes are encrypted end to end. The rule is NON_COMPLIANT if the encryption between nodes is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.5.14", "Description": "Checks if Kubernetes clusters require TLS/SSL encryption for API server connections. The rule is NON_COMPLIANT if the Kubernetes API server has the parameter --tls-security-mode not set to 'always'.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.5.15", "Description": "Checks if Kubernetes services are configured to require TLS for communication. The rule is NON_COMPLIANT if any service allows HTTP traffic without enforcing TLS.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.5.16", "Description": "Checks if a Kubernetes Deployment uses the FTP protocol for service communication. The rule is NON_COMPLIANT if the Deployment exposes a service with the FTP protocol enabled.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "1.2.5.17", "Description": "Checks if Network Policies or Security Groups in Kubernetes allow unrestricted incoming traffic ('0.0.0.0/0' or '::/0') only for authorized ports and protocols (TCP/UDP). The rule is NON_COMPLIANT if such policies do not specify authorized ports.", - "Name": "Kubernetes Network Policy / Kubernetes Security Groups", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.5: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policy / Kubernetes Security Groups" + "Service": "Core" } ] }, { "Id": "1.2.8.1", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the type configured in the rule parameter.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.2.8.2", "Description": "Verifies if a Kubernetes service that exposes a REST API is configured with an SSL certificate. The status is NON_COMPLIANT if the service is not using an SSL certificate for secure communication.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.2.8.3", "Description": "Checks if Kubernetes APIs are associated with Network Policies. The rule is NON_COMPLIANT for a Kubernetes API if it is not associated with a Network Policy.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.8.4", "Description": "Checks if Kubernetes Ingress resources are associated with Network Policies. The rule is NON_COMPLIANT if an Ingress resource is not associated with any Network Policy.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.8.5", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default self-signed certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default self-signed certificate.", - "Name": "Kubernetes Ingress", + "Name": "ETCD", "Checks": [ "etcd_no_auto_tls" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Ingress" + "Service": "ETCD" } ] }, { "Id": "1.2.8.6", "Description": "Checks if the Bitbucket source repository URL contains sign-in credentials. The result is NON_COMPLIANT if the URL contains any sign-in information and COMPLIANT if it doesn't.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "1.2.8.7", "Description": "Checks if Kubernetes Pods have public IP addresses. The rule is NON_COMPLIANT if the Pod's IP address is part of a public IP range.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.8", "Description": "Checks if Kubernetes persistent volumes are accessible to all users. The rule is NON_COMPLIANT if any persistent volumes are accessible to any user (i.e., public).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.2.8.9", "Description": "Checks if the Kubernetes NetworkPolicy allows all ingress traffic for all pods. The rule is NON_COMPLIANT if any NetworkPolicy allows traffic from all sources.", - "Name": "Kubernetes NetworkPolicy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "Core" } ] }, { "Id": "1.2.8.10", "Description": "Checks if the status of the Kubernetes deployment is AVAILABLE or UNAVAILABLE after the deployment execution on the pod. The rule is compliant if the status is AVAILABLE. For more information about deployments, see What is a deployment?", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.11", "Description": "Checks if Kubernetes Network Policies have 'AllowTraffic' enabled. The rule is NON_COMPLIANT for a Network Policy if 'AllowTraffic' is set to 'true'.", - "Name": "Kubernetes Network Policies", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policies" + "Service": "Core" } ] }, { "Id": "1.2.8.12", "Description": "Checks if the Kubernetes API server endpoint is not publicly accessible. The rule is NON_COMPLIANT if the endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.8.13", "Description": "Checks if Kubernetes Services are running in a private network. The rule is NON_COMPLIANT if a Service (ClusterIP, NodePort, or LoadBalancer) has a public endpoint exposed.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.14", "Description": "Checks if Kubernetes Services of type LoadBalancer have associated Ingress resources configured to use TLS certificates from a specified secret. This rule is NON_COMPLIANT if at least 1 LoadBalancer Service has an associated Ingress that is either not configured with a TLS certificate or uses a certificate not from the specified secret.", - "Name": "Kubernetes LoadBalancer Service and Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes LoadBalancer Service and Ingress" + "Service": "API Server" } ] }, { "Id": "1.2.8.15", "Description": "Checks if Kubernetes Services use TLS certificates provided by cert-manager or another certificate management solution. This rule is only applicable to Services with type LoadBalancer that handle HTTPS traffic, and does not apply to ClusterIP or NodePort Services.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.2.8.16", "Description": "Checks if a Kubernetes cluster has restricted external access settings. The rule is NON_COMPLIANT if the NetworkPolicy does not restrict ingress traffic on critical ports, or if restrictions are missing for services other than the desired ports.", - "Name": "Kubernetes NetworkPolicy", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "Core" } ] }, { "Id": "1.2.8.17", "Description": "This rule prevents incoming SSH requests to the Kubernetes cluster, effectively disabling SSH access to the nodes.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.2.8.18", "Description": "Checks if LoadBalancers are associated with an authorized Kubernetes Namespace. The rule is NON_COMPLIANT if LoadBalancers are associated with an unauthorized Namespace.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_namespace_lifecycle_plugin" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.8.19", "Description": "Checks if the Kubernetes ServiceAccount policy attached to the Pod prohibits public access. If the ServiceAccount policy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "1.2.8.20", "Description": "Checks if a Kubernetes deployment is using a specific network policies to control pod traffic, where the rule is NON_COMPLIANT if the deployment does not implement network policies for security.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.21", "Description": "Checks if default ports for SSH/RDP ingress traffic are unrestricted in Network Policies. The rule is NON_COMPLIANT if a Network Policy allows ingress from any source IP address for ports 22 (SSH) or 3389 (RDP).", - "Name": "Kubernetes Network Policies", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policies" + "Service": "Core" } ] }, { "Id": "1.2.8.22", "Description": "Checks if a Kubernetes Network Policy is configured with a user-defined policy for fragmented packets. The rule is NON_COMPLIANT if the default action for fragmented packets does not match the user-defined action in the network policy.", - "Name": "Kubernetes Network Policies", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policies" + "Service": "Core" } ] }, { "Id": "1.2.8.23", "Description": "Check Kubernetes Network Policies are associated with pod selector rules. This rule is NON_COMPLIANT if no Network Policies are associated with the selected pods, else COMPLIANT if any Network Policy is applied to the pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.24", "Description": "Checks if a Kubernetes Network Policy has any ingress or egress rules defined. The policy is considered NON_COMPLIANT if there are no rules specified in the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.2.8.25", "Description": "Checks if there are public routes in the Kubernetes network configuration that direct traffic to an external service or endpoint. The rule is NON_COMPLIANT if a network policy allows traffic from pods to external IPs that enable unrestricted access to the Internet.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.2.8.26", "Description": "Checks if Kubernetes clusters are running in a private network. The rule is NON_COMPLIANT if the cluster API server endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.8.27", "Description": "Checks if there are any Kubernetes Network Policies that are not the default Network Policy. The rule is NON_COMPLIANT if there are any Network Policies that are not the default Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.28", "Description": "Checks if the Kubernetes Pods running in the cluster are not exposed to the public internet. The rule is NON_COMPLIANT if the Pod's service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.29", "Description": "Checks if the Kubernetes services are not exposed externally. The rule is NON_COMPLIANT if the service type is 'LoadBalancer' or 'NodePort' which makes them accessible externally.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.2.8.30", "Description": "Checks if Kubernetes services have network policies in place to block unauthorized access. The rule is NON_COMPLIANT if network policies are not defined to restrict access to services.", - "Name": "Kubernetes Network Policies", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policies" + "Service": "Core" } ] }, { "Id": "1.2.8.31", "Description": "Checks if the required network policies are configured to restrict public access for the specified Kubernetes pods. The status is only NON_COMPLIANT when the network policies do not match the predefined rules for public access control.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.2.8.32", "Description": "Verifies if the required network policies for public access restrictions are configured at the cluster level. The rule is NON_COMPLIANT if the configuration does not align with defined policies or defaults for restricting external access.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.2.8.33", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.2.8.34", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public access. The rule checks the access modes and security contexts configured for the persistent volume claims and associated pods.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.2.8.35", "Description": "Checks if your Kubernetes buckets (storage classes or persistent volume claims) do not allow public write access. The rule checks the access policies and permissions defined for the storage resources.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.36", "Description": "Checks if a Kubernetes pod is deployed within a specific namespace or within a list of approved node selectors. The rule is NON_COMPLIANT if a pod is not deployed within the specified namespace or if its node selector does not match the approved criteria.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "1.2.8.37", "Description": "Checks if direct internet access is disabled for a Kubernetes pod. The rule is NON_COMPLIANT if a Kubernetes pod has an external IP assigned, allowing internet access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.2.8.38", "Description": "Checks if a Kubernetes Service Endpoint for the specified service is created for each Kubernetes namespace. The status is NON_COMPLIANT if a namespace does not have an endpoint created for the service.", - "Name": "Kubernetes Service Endpoint", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Service Endpoint" + "Service": "API Server" } ] }, { "Id": "1.2.8.39", "Description": "Checks if there are unused Network Policies. The rule is COMPLIANT if each Network Policy is associated with a namespace. The rule is NON_COMPLIANT if a Network Policy is not associated with any namespace.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.2.8.40", "Description": "Checks if DNS resolution from the Accepter/Requester VPC to the private IP is enabled in Kubernetes. A NON_COMPLIANT status is indicated if DNS resolution from the Accepter/Requester VPC to the private IP is not enabled.", - "Name": "Kubernetes DNS (CoreDNS)", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes DNS (CoreDNS)" + "Service": "API Server" } ] }, { "Id": "1.2.8.41", "Description": "Checks if Network Policies in Kubernetes allow unrestricted incoming traffic ('0.0.0.0/0' or '::/0') only for authorized ports. The rule is NON_COMPLIANT if such Network Policies do not have ports specified in the rule parameters.", - "Name": "Network Policies", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Network Policies" + "Service": "Core" } ] }, { "Id": "1.2.8.42", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.2.8.43", "Description": "Checks if a Kubernetes NetworkPolicy has any ingress or egress rules defined. The NetworkPolicy is NON_COMPLIANT if no rules are present.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.2.8.44", "Description": "Checks whether a Kubernetes Network Policy contains any ingress or egress rules. This rule is NON_COMPLIANT if a Network Policy does not contain any ingress or egress rules.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.2.8.45", "Description": "Checks if a Kubernetes NetworkPolicy has any ingress or egress rules defined. The NetworkPolicy is considered NON_COMPLIANT if there are no rules present within it.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.2.8.46", "Description": "Checks whether Kubernetes NetworkPolicy contains ingress or egress rules. This policy is COMPLIANT if it contains at least one rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.2.8.47", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no ingress or egress rules present within the NetworkPolicy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.2.8: Network security controls (NSCs) are configured and maintained.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.1", "Description": "Checks if a Kubernetes Ingress resource is using an Ingress Controller that is compliant with the specified security policies (e.g., a Web Application Firewall). The rule is NON_COMPLIANT if an Ingress resource is not associated with a compliant Ingress Controller or if the Ingress Controller does not meet the security policy criteria defined in the rule parameters.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "1.3.1.2", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the service type configured in the rule parameter.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.3.1.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS settings. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.4", "Description": "Checks if Kubernetes Ingress resources are associated with NetworkPolicies. The rule is NON_COMPLIANT for a Kubernetes Ingress if it is not associated with a NetworkPolicy.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.5", "Description": "Checks if Kubernetes Ingress resources are associated with any network policies. The rule is NON_COMPLIANT if an Ingress resource is not associated with a network policy.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.6", "Description": "Verifies if the TLS certificate associated with a Kubernetes Ingress resource is a custom certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default or self-signed TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.7", "Description": "Checks if the Bitbucket source repository URL contains sign-in credentials. The rule is NON_COMPLIANT if the URL contains any sign-in information and COMPLIANT if it doesn't.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "1.3.1.8", "Description": "Checks if Kubernetes pods are accessible from outside the cluster via their services. The rule is NON_COMPLIANT if the service type is LoadBalancer or NodePort, which exposes the pods to the public.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "1.3.1.9", "Description": "Checks if Kubernetes persistent volume snapshots are publicly accessible. The rule is NON_COMPLIANT if any Kubernetes persistent volume snapshots are publicly accessible.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.3.1.10", "Description": "Checks if the Kubernetes NetworkPolicy allows access for all pods. The rule is NON_COMPLIANT if 'allowAll' is present and set to true.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.11", "Description": "Checks if the status of a Kubernetes configuration or deployment is healthy (COMPLIANT) or unhealthy (NON_COMPLIANT) after applying the configuration to the pod. The rule is compliant if the pod is running without errors. For more information about pod statuses, see Kubernetes Pod Lifecycle.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.12", "Description": "Checks if Kubernetes Network Policies have 'AllowAllIngress' configured. The rule is NON_COMPLIANT for a Network Policy if 'AllowAllIngress' is set to 'true'.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.13", "Description": "Checks if the Kubernetes API server endpoint is not publicly accessible. The rule is NON_COMPLIANT if the endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.14", "Description": "Checks if Kubernetes clusters are configured with custom network policies. The rule is NON_COMPLIANT for a Kubernetes cluster if it is using the default network policies.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.15", "Description": "Checks if Kubernetes services are within a defined Network Policy. The rule is NON_COMPLIANT if a service is exposed publicly without proper network isolation.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.16", "Description": "Checks if Kubernetes Ingress resources have TLS settings configured to use certificates from a trusted certificate management service. This rule is NON_COMPLIANT if at least 1 Ingress has at least 1 TLS entry that is configured without a certificate or is configured with a certificate different from a trusted certificate management service.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.17", "Description": "Checks if Ingress resources in Kubernetes use SSL certificates provided by a certificate management solution (e.g., Cert-Manager). To use this rule, ensure an Ingress resource is configured with TLS settings. This rule is only applicable to Ingress resources and does not check LoadBalancer services directly.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.18", "Description": "Checks if a Kubernetes Cluster has network policies that restrict public access. The rule is NON_COMPLIANT if network policies allow access to any port other than Port 22.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.19", "Description": "In Kubernetes, the rule INCOMING_SSH_DISABLED corresponds to a NetworkPolicy that restricts incoming traffic on port 22 (SSH) to prevent unauthorized access, reflecting the restricted-ssh policy. This NetworkPolicy can be used to control the flow of traffic to pods in a namespace, effectively disabling incoming SSH access as specified by the rule name.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.20", "Description": "The rule identifier for Kubernetes resources is commonly the name of the resource, while the rule name can refer to the specific configuration or a higher-level abstraction. For example, in Kubernetes, a Deployment (which could represent multiple instances of pods) could be associated with a label that identifies it, but the deployment itself may have a distinct name. This mirrors the difference between the rule identifier and rule name for EC2 instances in VPC.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.21", "Description": "Checks if Kubernetes services are associated with an authorized namespace. The rule is NON_COMPLIANT if services are linked to an unauthorized namespace.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_namespace_lifecycle_plugin" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.22", "Description": "Checks if the Kubernetes Service account policy attached to the Pod prohibits public access. If the Service account policy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.23", "Description": "Checks if a Kubernetes Pod is allowed access to a specific namespace. The rule is NON_COMPLIANT if the Pod does not have appropriate Network Policies enabling access to the namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -1129,1268 +1129,1268 @@ { "Id": "1.3.1.25", "Description": "Checks if a Kubernetes Network Policy is configured with a user defined default action for fragmented packets. The rule is NON_COMPLIANT if the default action for fragmented packets does not match with user defined default action.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.26", "Description": "Check if Kubernetes NetworkPolicy has ingress or egress rules defined. The policy is NON_COMPLIANT if no ingress or egress rules are defined, otherwise it is COMPLIANT if at least one rule exists.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.27", "Description": "Checks if a Kubernetes NetworkPolicy object has any ingress or egress rules defined. The rule is NON_COMPLIANT if there are no rules in the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.28", "Description": "Checks if there are public routes in the Kubernetes networking configuration to an Internet Gateway (IGW). The rule is NON_COMPLIANT if a route to an IGW has a destination CIDR block of '0.0.0.0/0' or '::/0' or if a destination CIDR block does not match the rule parameter.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.3.1.29", "Description": "Checks if Kubernetes services are configured to only be accessible within a cluster network. The rule is NON_COMPLIANT if a service has a type of LoadBalancer or NodePort, which exposes it publicly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.30", "Description": "Checks if there are any Kubernetes Network Policies that are not the default Network Policy. The rule is NON_COMPLIANT if there are any Network Policies that are not the default Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.31", "Description": "Checks if the Kubernetes services of type LoadBalancer are not publicly accessible. The rule is NON_COMPLIANT if the externalTrafficPolicy field is set to Local, allowing direct access from outside the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.32", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the service is exposed through a LoadBalancer type service or has a public IP assigned.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.33", "Description": "Checks if a Kubernetes cluster has 'NetworkPolicy' applied. The rule is NON_COMPLIANT if 'NetworkPolicy' is not enforced or if the configuration.networkPolicy field is 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.34", "Description": "Checks if Kubernetes services have network policies that block public access to sensitive endpoints. The rule is NON_COMPLIANT if network policies are not in place to restrict public access to these services.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.35", "Description": "Checks if the required Network Policies to restrict public access are configured at the cluster level. The rule is only NON_COMPLIANT when the specified NetworkPolicy settings do not match the desired configuration.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.3.1.36", "Description": "Checks if the required network policies for pod security are configured at the namespace level. The rule is NON_COMPLIANT if the configuration item does not align with one or more settings from the defined policies (or default).", - "Name": "NetworkPolicy", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "Core" } ] }, { "Id": "1.3.1.37", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.1.38", "Description": "Checks if your Kubernetes Secrets do not allow public access. The rule checks the Secret's permissions (RBAC), the Namespace isolation, and the network policies.", - "Name": "Kubernetes Secrets", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Secrets" + "Service": "RBAC" } ] }, { "Id": "1.3.1.39", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public write access by evaluating the access modes and appropriate role-based access control (RBAC) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.3.1.40", "Description": "Checks if a Kubernetes Pod is running within a specific Namespace or within a list of approved Labels. The rule is NON_COMPLIANT if a Pod is not running within the specified Namespace or if its Labels are not included in the parameter list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.41", "Description": "Checks if direct internet access is disabled for a Kubernetes pod. The rule is NON_COMPLIANT if a pod has an external access configuration or uses LoadBalancer type service.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.42", "Description": "Checks if a Kubernetes Service has an Endpoint for each corresponding Pod in the specified namespace. The rule is NON_COMPLIANT if a Kubernetes Service does not have an Endpoint created for its Pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.43", "Description": "Checks if there are unused network policies. The rule is COMPLIANT if each network policy is associated with a pod or service. The rule is NON_COMPLIANT if a network policy is not associated with a pod or service.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.3.1.44", "Description": "Checks if DNS resolution between pods in different namespaces within the Kubernetes cluster is enabled. The rule is NON_COMPLIANT if DNS resolution between those pods is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.1.45", "Description": "Verifies that NetworkPolicies are configured to restrict unrestricted incoming traffic ('0.0.0.0/0' or '::/0') and only allow inbound TCP or UDP connections on specified ports. The rule is considered NON_COMPLIANT if any NetworkPolicy does not specify allowed ports.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.46", "Description": "Checks if both network policies in Kubernetes are in 'Active' status. The rule is NON_COMPLIANT if one or both network policies are not 'Active'.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.3.1.47", "Description": "Checks if a Kubernetes Network Policy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules specified within the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.48", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if no rules are present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.49", "Description": "Checks whether a Kubernetes Ingress resource has any associated Ingress rules for routing traffic. This state is considered NON_COMPLIANT if the Ingress resource does not contain any Ingress rules.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.1.50", "Description": "Checks if a Kubernetes Network Policy has any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined within the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.1.51", "Description": "Checks whether a Kubernetes NetworkPolicy contains at least one rule. This NetworkPolicy is COMPLIANT if it contains at least one rule, and NON_COMPLIANT otherwise.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.1.52", "Description": "Checks if a Kubernetes Network Policy exists within a namespace. The policy is NON_COMPLIANT if there are no Network Policies defined in the namespace.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.1: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.2.1", "Description": "Checks if a Kubernetes Ingress resource is using an associated NetworkPolicy to control access. The rule is NON_COMPLIANT if a NetworkPolicy is not used or if the used NetworkPolicy does not match the criteria specified in the rule parameter.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.2.2", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the endpoint type configured in the rule parameter.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.3.2.3", "Description": "Verifies if a Kubernetes Ingress resource is configured with TLS settings. The status is NON_COMPLIANT if the Ingress does not have TLS defined, indicating that SSL certificates are not associated.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.2.4", "Description": "Checks if Kubernetes services are protected by Network Policies. The rule is NON_COMPLIANT for a Kubernetes service if it is not associated with a Network Policy.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.3.2.5", "Description": "Checks if Kubernetes Ingress resources are associated with Network Policies. The rule is NON_COMPLIANT if an Ingress resource is not associated with a Network Policy that restricts traffic.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.2.6", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default TLS certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.2.7", "Description": "Verifies if the Bitbucket source repository URL includes authentication credentials. The status is NON_COMPLIANT if the URL contains any credentials, otherwise it is COMPLIANT.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "1.3.2.8", "Description": "Checks if Kubernetes pods are running with public IP addresses. The rule is NON_COMPLIANT if the pod's service type is set to 'LoadBalancer' and an external IP is assigned.", - "Name": "Kubernetes Pods", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Pods" + "Service": "API Server" } ] }, { "Id": "1.3.2.9", "Description": "Checks if Kubernetes PersistentVolumeClaims (PVCs) are using publicly accessible storage classes. The rule is NON_COMPLIANT if any PVCs are using public storage classes that expose sensitive data.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.3.2.10", "Description": "Checks if the Kubernetes NetworkPolicy allows access for all clients. The rule is NON_COMPLIANT if 'allow All' is present and set to true.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.11", "Description": "Checks if the status of a Kubernetes deployment is AVAILABLE or NOT_AVAILABLE after the deployment execution on the cluster. The rule is compliant if the field status is AVAILABLE. For more information about deployments, see What is a deployment?.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "1.3.2.12", "Description": "Checks if Kubernetes Cluster has 'AutoAcceptSharedAttachments' enabled for network routing. The rule is NON_COMPLIANT for a Cluster if 'AutoAcceptSharedAttachments' is set to 'enable'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.13", "Description": "Checks if the Kubernetes API server endpoint is configured to be private and not publicly accessible. The rule is NON_COMPLIANT if the endpoint is accessible from the public internet.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.2.14", "Description": "Checks if Kubernetes pods are configured with a custom network policy. The rule is NON_COMPLIANT for a pod if it is using the default network policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.15", "Description": "Checks if Kubernetes OpenSearch deployments are within a Kubernetes cluster and not exposed through a public service. The rule is NON_COMPLIANT if an OpenSearch deployment is exposed via a LoadBalancer service type.", - "Name": "Kubernetes OpenSearch", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes OpenSearch" + "Service": "Core" } ] }, { "Id": "1.3.2.16", "Description": "Verifies if Kubernetes Ingress resources are configured with TLS settings that utilize certificates from a configured certificate manager, such as Cert-Manager. The rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 rule that is configured without a TLS certificate or is configured with a certificate that is not managed by the certificate manager.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "1.3.2.17", "Description": "Checks if the Kubernetes Ingress uses SSL certificates provided by a Certificate Manager. To use this rule, configure an Ingress resource with SSL or HTTPS settings. This rule is only applicable to Ingress resources. This rule does not check Services of type NodePort or ClusterIP.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.3.2.18", "Description": "Checks if a Kubernetes account has network policies configured to prevent public access. The rule is NON_COMPLIANT if any network policies allow traffic from outside the cluster or if services other than Port 22 are exposed without proper restrictions.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.19", "Description": "The Kubernetes equivalent of this rule involves creating a NetworkPolicy that restricts incoming SSH traffic (port 22) to pods, effectively disabling SSH access for incoming connections. The rule identifier is designed to prevent unauthorized access to the service running in the cluster.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.20", "Description": "The rule identifier (INSTANCES_IN_VPC) represents a specific rule for managing instances in a VPC, while the rule name (ec2-instances-in-vpc) provides a human-readable label for the same rule within a Kubernetes context. This can be associated with network policies or security groups managing pod communication within a cluster.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.21", "Description": "Checks if Kubernetes services are attached to authorized namespaces. The rule is NON_COMPLIANT if services are attached to unauthorized namespaces.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_namespace_lifecycle_plugin" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.2.22", "Description": "Checks if the Kubernetes Pod's NetworkPolicy prevents public access to the Pods. If the NetworkPolicy allows public access, it is considered NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.23", "Description": "Checks if a Kubernetes deployment is configured to run within a specified network policy. The rule is NON_COMPLIANT if the deployment is not using the appropriate network policy to restrict access to the cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.24", "Description": "Checks if the Kubernetes NetworkPolicy allows unrestricted ingress traffic on ports 22 (SSH) and 3389 (RDP) from any source IP. The rule is NON_COMPLIANT if a NetworkPolicy permits ingress on these ports without restrictions.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.25", "Description": "Checks if a Kubernetes NetworkPolicy is configured with a user-defined action for fragmented packets. The rule is NON_COMPLIANT if the action for fragmented packets does not match the user-defined default action.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.26", "Description": "Verify if a Kubernetes NetworkPolicy is associated with at least one ingress or egress rule. The policy is NON_COMPLIANT if there are no ingress or egress rules defined, otherwise COMPLIANT if at least one rule exists.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.27", "Description": "Checks if a Kubernetes Network Policy contains ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined in the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.2.28", "Description": "Verifies if there are Kubernetes services with type LoadBalancer that expose ports to external traffic. The status is NON_COMPLIANT if a service allows unrestricted access (i.e., has '0.0.0.0/0' in its ingress rules) or if the service does not comply with the specified network policies.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.3.2.29", "Description": "Checks if Kubernetes pods are running inside a Kubernetes cluster network (VPC equivalent). The rule is NON_COMPLIANT if a pod is exposed via a public IP address or LoadBalancer service type without appropriate network policies.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.30", "Description": "Checks if there are any Kubernetes NetworkPolicies that are not the default NetworkPolicy. The rule is NON_COMPLIANT if there are any NetworkPolicies that are not the default NetworkPolicy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.31", "Description": "Checks if the Kubernetes Database (e.g., PostgreSQL, MySQL) instances are not publicly accessible. The rule is NON_COMPLIANT if the service type is LoadBalancer or Ingress and has an external IP.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.32", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the service is exposed via a LoadBalancer type with an external IP address.", - "Name": "Kubernetes Cluster", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Cluster" + "Service": "API Server" } ] }, { "Id": "1.3.2.33", "Description": "Checks if a Kubernetes Cluster has 'Network Policy' enabled to restrict pod communication. The rule is NON_COMPLIANT if 'networkPolicy' is not enabled or if the Network Policy configuration field is 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.34", "Description": "Checks if Kubernetes Secrets have restrictive access control policies. The rule is NON_COMPLIANT if Secrets are not configured with appropriate role-based access controls (RBAC) to restrict access.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.3.2.35", "Description": "Checks if the required network policies are configured at the namespace level. The rule is only NON_COMPLIANT when the network policies defined do not match the corresponding settings in the Kubernetes configuration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.36", "Description": "Checks if the required network policies are configured at the namespace level. The rule is NON_COMPLIANT if the configuration item does not match one or more settings from parameters (or default).", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.3.2.37", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.3.2.38", "Description": "Checks if your Kubernetes PersistentVolumeClaims do not allow public access. The rule verifies the access modes and any role-based access control (RBAC) policies applied to the persistent volumes.", - "Name": "Kubernetes Persistent Storage", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Persistent Storage" + "Service": "RBAC" } ] }, { "Id": "1.3.2.39", "Description": "Checks if your Kubernetes Persistent Volume Claims (PVCs) do not allow public write access. The rule examines the access modes defined in the PVC, the associated Persistent Volumes (PVs), and the underlying StorageClass configurations to ensure they do not permit public write operations.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.3.2.40", "Description": "Checks if a Kubernetes pod is deployed within a specific namespace or within a list of approved network policies. The rule is NON_COMPLIANT if a pod is not deployed within the specified namespace or if the applied network policy does not match the approved list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.41", "Description": "Checks if direct internet access is disabled for a Kubernetes Pod. The rule is NON_COMPLIANT if a Pod is configured with a public IP or can communicate with the internet directly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.42", "Description": "Checks if a Kubernetes Service has an Endpoints object created for each defined Service. The rule is NON_COMPLIANT if a Kubernetes Service does not have an Endpoints object created.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.3.2.43", "Description": "Checks if there are unused network policies in Kubernetes. The rule is COMPLIANT if each network policy is associated with a pod or namespace. The rule is NON_COMPLIANT if a network policy is not associated with a pod or namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.44", "Description": "Checks if DNS resolution from Kubernetes cluster to private IP is enabled. The rule is NON_COMPLIANT if DNS resolution from Kubernetes cluster to private IP is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.45", "Description": "Checks if Network Policies or Security Groups in Kubernetes allow unrestricted incoming traffic ('0.0.0.0/0') only for TCP or UDP connections on authorized ports. The rule is NON_COMPLIANT if such policies or configurations do not restrict to specified ports.", - "Name": "Network Policies", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Network Policies" + "Service": "Core" } ] }, { "Id": "1.3.2.46", "Description": "Verifies if both Kubernetes cluster nodes in a specified node pool are in Ready status. The rule is NON_COMPLIANT if one or more nodes are in NotReady status.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.3.2.47", "Description": "Checks if a Kubernetes Network Policy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined within the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.2.48", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The NetworkPolicy is NON_COMPLIANT if no ingress or egress rules are present.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.49", "Description": "Checks whether a Kubernetes Network Policy contains any ingress or egress rules. This policy is NON_COMPLIANT if a Network Policy does not contain any ingress or egress rules.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.2.50", "Description": "Checks if the Network Policies in the Kubernetes cluster contain any ingress or egress rules. The policy is marked NON_COMPLIANT if there are no rules present within a Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.3.2.51", "Description": "Checks whether the Kubernetes NetworkPolicy includes at least one ingress or egress rule. This policy is COMPLIANT if it contains at least one rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.3.2.52", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no ingress or egress rules defined within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.3.2: Network access to and from the cardholder data environment is restricted.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.4.1.1", "Description": "Checks if a Kubernetes Ingress resource is using an NGINX Ingress Controller with a specified set of annotations for WAF rules. The rule is NON_COMPLIANT if an Ingress resource does not use the specified NGINX Ingress Controller or if the associated WAF settings do not match those defined in the rule parameters.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.1.2", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the service type configured in the rule parameter.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.4.1.3", "Description": "Checks if Kubernetes clusters are configured with a custom network policy. The rule is NON_COMPLIANT for a Kubernetes deployment if it is using the default network policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.1.4", "Description": "The rule identifier INSTANCES_IN_VPC and rule name ec2-instances-in-vpc represent configurations that allow EC2 instances within a specific Virtual Private Cloud (VPC) to communicate with each other. In Kubernetes, a similar concept entails configuring network policies that control traffic between pods within a namespace or cluster, ensuring that only authorized communications are permitted.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.1.5", "Description": "Checks if network policies are enforced for authorized namespaces in Kubernetes. The rule is NON_COMPLIANT if network policies are applied to unauthorized namespaces.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.1.6", "Description": "Check if there are public routes in the route table in Kubernetes. The rule is NON_COMPLIANT if there is an ingress rule allowing traffic to pod IPs or services exposed to the internet with a target CIDR block of '0.0.0.0/0' or if the ingress rule does not match the specified parameters.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.4.1.7", "Description": "Checks if Kubernetes cluster has network policies enabled. The rule is NON_COMPLIANT if network policies are not enabled or if any namespace does not have at least one network policy configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.1.8", "Description": "Checks if a Kubernetes Pod is deployed within a specified namespace or within a list of approved labels. The rule is NON_COMPLIANT if a Pod is not deployed within the specified namespace or if its labels do not match the approved list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.1.9", "Description": "Verifies that DNS resolution is enabled for services within the Kubernetes cluster and that pods can resolve private IPs appropriately. The rule is NON_COMPLIANT if DNS resolution from a pod in one namespace to a service in another namespace using private IP addresses is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.1.10", "Description": "Checks if both Kubernetes network connections (e.g., ingress controllers or service mesh tunnels) are healthy and operational. The rule is NON_COMPLIANT if one or both connections report an unhealthy status.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.1: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.4.2.1", "Description": "Checks if a Kubernetes Ingress resource is using a configured Network Policy. The rule is NON_COMPLIANT if no Network Policy is applied to the Ingress or if the applied Network Policy does not match the expected configuration defined in the rule parameters.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.2.2", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the type configured in the rule parameter.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.4.2.3", "Description": "Checks if a Kubernetes Ingress resource has an associated TLS secret. The rule is NON_COMPLIANT if the Ingress does not have a defined TLS configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.2.4", "Description": "Checks if Kubernetes APIs are associated with Network Policies. The rule is NON_COMPLIANT for a Kubernetes API if it is not associated with a Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.5", "Description": "Checks if Kubernetes Ingress resources are associated with a Network Policy. The rule is NON_COMPLIANT if an Ingress resource is not associated with any Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.6", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate instead of a custom one.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.2.7", "Description": "Checks if the Bitbucket source repository URL contains sign-in credentials or not. The rule is NON_COMPLIANT if the URL contains any sign-in information and COMPLIANT if it doesn't.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "1.4.2.8", "Description": "Checks if Kubernetes services are exposed to the public. The rule is NON_COMPLIANT if the service type is set to LoadBalancer and it has an external IP address.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.4.2.9", "Description": "Checks if Kubernetes persistent volume snapshots are public. The rule is NON_COMPLIANT if any Kubernetes persistent volume snapshots are public.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.10", "Description": "Checks if the Kubernetes NetworkPolicy allows all Pods to communicate with each other. The policy is NON_COMPLIANT if 'allowAll' is present and set to true.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, @@ -2409,78 +2409,66 @@ { "Id": "1.4.2.12", "Description": "Checks if Kubernetes Network Policies have 'Ingress' rules set to allow traffic from specific namespaces. The rule is NON_COMPLIANT for a Network Policy if 'Ingress' rules allow traffic from any source.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.2.13", "Description": "Checks if the Kubernetes API server endpoint is not publicly accessible. The rule is NON_COMPLIANT if the endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.4.2.14", "Description": "Checks if Kubernetes clusters are running in a private network. The rule is NON_COMPLIANT if a Kubernetes service has a public IP address exposed.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.15", "Description": "Checks if Kubernetes Ingress resources are configured to use TLS certificates from a trusted certificate provider (like Cert Manager). This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 HTTPS entry that is configured without a TLS certificate or is configured with a certificate not issued by a trusted certificate authority.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Ingress" - } - ] - }, - { - "Id": "1.4.2.16", - "Description": "Checks if the Ingress Controllers in Kubernetes use SSL certificates provided by a certificate manager such as cert-manager or AWS Certificate Manager. To use this rule, ensure that Ingress resources are configured with HTTPS routes. This rule is applicable to Ingress Controllers and does not check for LoadBalancer services without an Ingress configuration.", - "Name": "Ingress Controller", - "Checks": [], - "Attributes": [ - { - "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "1.4.2.17", "Description": "Checks if an account in Kubernetes has network policies that restrict public access. The rule is NON_COMPLIANT if AllowAllIngress is true, or if true, ports other than Port 22 are listed in IngressRules.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -2499,98 +2487,98 @@ { "Id": "1.4.2.19", "Description": "Checks if Kubernetes Ingress Controllers are attached to an authorized namespace. The rule is NON_COMPLIANT if Ingress Controllers are attached to an unauthorized namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.20", "Description": "Checks if the Kubernetes Pod Security Policy attached to the Pod resource prohibits public access. If the Pod Security Policy allows public access it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.21", "Description": "Checks if a Kubernetes Pod is allowed access to a virtual private cloud (VPC). The rule is NON_COMPLIANT if the Pod does not specify a VPC network (using the appropriate CNI plugin).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.22", "Description": "Checks if Kubernetes network policies allow unrestricted ingress traffic for SSH (port 22) and RDP (port 3389) to the specified pods. The rule is NON_COMPLIANT if a network policy does not restrict ingress traffic from certain CIDR blocks for these ports.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.4.2.23", "Description": "Checks if a Kubernetes NetworkPolicy is configured with a user-defined ingress or egress rule that includes specific handling of fragmented packets. The rule is NON_COMPLIANT if the handling of fragmented packets does not match the user-defined rule.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.4.2.24", "Description": "Check if a Kubernetes Network Policy is associated with PodSelectors that define stateful or stateless traffic rules. This rule is NON_COMPLIANT if no PodSelectors are defined for the Network Policy, otherwise it is COMPLIANT if any PodSelector exists.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.2.25", "Description": "Checks if a Kubernetes NetworkPolicy contains ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined in a NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.4.2.26", "Description": "Checks for public routes in the Kubernetes network configuration. The rule is NON_COMPLIANT if a service is exposed to the internet with a LoadBalancer or NodePort type that allows access to all IP ranges (0.0.0.0/0 or ::/0) without restrictions on CIDR blocks.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, @@ -2609,4228 +2597,3886 @@ { "Id": "1.4.2.28", "Description": "Checks if there are any Kubernetes Network Policies that are not the default Network Policy. The rule is NON_COMPLIANT if there are any Network Policies that are not the default Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.29", "Description": "Checks if the Kubernetes databases are not publicly accessible. The rule is NON_COMPLIANT if the service is exposed through a LoadBalancer type or NodePort type which allows external traffic.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.30", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the externalIPs field is set in the Service configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.4.2.31", "Description": "Checks if a Kubernetes cluster has the NetworkPolicy enabled for enhanced security. The rule is NON_COMPLIANT if NetworkPolicy is not enabled or if there are no defined ingress/egress rules that enforce strict network traffic controls.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.32", "Description": "Checks if Kubernetes Services have `spec.type` set to `ClusterIP` to restrict external access. The rule is NON_COMPLIANT if `spec.type` is set to `NodePort` or `LoadBalancer`, allowing external access.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.4.2.33", "Description": "Checks if the required NetworkPolicy settings for public access are configured at the namespace level in Kubernetes. The rule is only NON_COMPLIANT when the NetworkPolicy does not restrict traffic accordingly to the desired configuration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.34", "Description": "Verifies that the necessary Kubernetes Network Policy measures are enforced at the cluster level. The rule is NON_COMPLIANT if the network policies do not align with the specified requirements or defaults.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.35", "Description": "Checks if Kubernetes ConfigMaps and Secrets are publicly accessible. The rule is NON_COMPLIANT if a ConfigMap or Secret is not listed in the excludedPublicConfigMaps and excludedPublicSecrets parameters and is exposed through a public service.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.4.2.36", "Description": "Checks if your Kubernetes Pods do not allow unauthorized access by verifying Network Policies, Pod Security Policies, and Role-Based Access Control (RBAC) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.4.2.37", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public write access. The rule checks the Volume Permissions, StorageClass settings, and Role-Based Access Control (RBAC) configurations.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.4.2.38", "Description": "Checks if a Kubernetes pod is deployed in a specific namespace and if its node is part of an approved node pool. The rule is NON_COMPLIANT if a pod is not deployed within the specified namespace or if its node is not included in the parameter list of approved node pools.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.39", "Description": "Checks if direct internet access is disabled for a Kubernetes pod. The rule is NON_COMPLIANT if a pod is internet-enabled (i.e., has an external IP or is not using a NetworkPolicy to restrict internet access).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.40", "Description": "Checks if Kubernetes Endpoints for the service specified are created for each namespace. The rule is NON_COMPLIANT if a namespace doesn't have an Endpoint created for the specified service.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.41", "Description": "Checks if there are unused network policies. The rule is COMPLIANT if each network policy is associated with a pod or namespace. The rule is NON_COMPLIANT if a network policy is not associated with a pod or namespace.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.2.42", "Description": "Checks if DNS resolution from the Kubernetes pod network to the service's private IP is enabled. The rule is NON_COMPLIANT if DNS resolution from the pod network to the service's private IP is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.43", "Description": "Validates that Kubernetes NetworkPolicies permit only specific ingress traffic, disallowing unrestricted access ('0.0.0.0/0' or '::/0') and restricting allowed protocols (TCP or UDP) to defined ports. A NetworkPolicy is deemed NON_COMPLIANT if it allows access on ports that are not specified in the policy criteria.", - "Name": "Kubernetes NetworkPolicy", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "Core" } ] }, { "Id": "1.4.2.44", "Description": "Checks if both Kubernetes network interfaces (e.g., pod network and service network) are operational. The rule is NON_COMPLIANT if one or both interfaces are not responding.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.4.2.45", "Description": "Checks if a Kubernetes Network Policy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.2.46", "Description": "Checks if a Kubernetes Network Policy defines any ingress or egress rules. The policy is NON_COMPLIANT if no rules are present within the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.2.47", "Description": "Checks whether a Kubernetes NetworkPolicy contains any ingress or egress rules. This policy is NON_COMPLIANT if a NetworkPolicy does not contain any rules.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.4.2.48", "Description": "Checks if Kubernetes Network Policies contain any rules. The policy is NON_COMPLIANT if there are no rules present within a Kubernetes Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.2.49", "Description": "Checks whether an Ingress resource in Kubernetes has defined annotations for security policies. This Ingress is COMPLIANT if it includes at least one security policy annotation and NON_COMPLIANT otherwise.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.2.50", "Description": "Checks if a Kubernetes Network Policy is defined for a namespace. The policy is NON_COMPLIANT if there are no Network Policies present within the namespace.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.2: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.3.1", "Description": "Checks if a Kubernetes NetworkPolicy is configured with a user-defined default action for fragmented packets. The rule is NON_COMPLIANT if the default action for fragmented packets does not match the user-defined default action.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.3: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.3.2", "Description": "Checks if a Kubernetes Network Policy is configured with a user-defined default action for ingress and egress traffic. This rule is NON_COMPLIANT if the default action for traffic does not match the user-defined default action.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.3: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.4.3.3", "Description": "Check Kubernetes NetworkPolicy is defined with at least one ingress or egress rule. This rule is NON_COMPLIANT if no ingress or egress rules are included in the NetworkPolicy else COMPLIANT if any one of the rules exists.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.3: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.4.4.1", "Description": "Checks if a Kubernetes Ingress resource is using a specific NetworkPolicy. The rule is NON_COMPLIANT if a NetworkPolicy is not applied to the Ingress or if the applied NetworkPolicy does not match the specified criteria.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.4.2", "Description": "Checks if Kubernetes Ingress resources are configured with the specified type in the rule parameter. The rule returns NON_COMPLIANT if the Ingress resource does not match the specified configuration type set in the rule parameter.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.4.4.3", "Description": "Checks if Kubernetes clusters are configured with a custom network policy. The rule is NON_COMPLIANT for a Kubernetes cluster if it is using the default network policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.4.4", "Description": "Kubernetes equivalent for managing instances within a specific pod network, ensuring that the pods communicate internally while restricting external access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.4.5", "Description": "Checks if ingress or egress network policies are attached to an authorized Kubernetes namespace. The rule is NON_COMPLIANT if network policies are attached to an unauthorized namespace.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.4.4.6", "Description": "Checks if there are public ingress rules in the Kubernetes NetworkPolicy that allow traffic from external sources. The rule is NON_COMPLIANT if a NetworkPolicy allows traffic from any external IP address (e.g., 0.0.0.0/0) or if an ingress rule does not match the specified allowed source CIDR blocks.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.4.4.7", "Description": "Checks if a Kubernetes cluster has network policies implemented. The rule is NON_COMPLIANT if network policies are not defined or if the policies.allowIngress field is 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.4.8", "Description": "Checks if a Kubernetes pod is deployed within a specific namespace or within a list of approved labels. The rule is NON_COMPLIANT if a pod is not deployed within the specified namespace or if its labels are not included in the parameter list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.4.9", "Description": "Verifies whether DNS resolution between the accepter/requester VPC and private IP is enabled in Kubernetes. The state is considered NON_COMPLIANT if DNS resolution from the specified VPC to the private IP is not enabled.", - "Name": "Kubernetes DNS", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes DNS" + "Service": "API Server" } ] }, { "Id": "1.4.4.10", "Description": "Checks if both Kubernetes Network Policies associated with the pod are in ENFORCED status. The rule is NON_COMPLIANT if one or both policies are in DISABLED status.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.4.4: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.5.1", "Description": "Checks if Kubernetes Pods are configured to use public IP addresses for their Network Interfaces. The rule is NON_COMPLIANT if the default Pod specification has at least 1 Network Interface with 'hostNetwork' set to 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.4.5: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.4.5.2", "Description": "Checks if Kubernetes Pods are configured to share the host's process namespace. The rule is NON_COMPLIANT if the hostPID parameter is set to 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostPID_containers" ], "Attributes": [ { "Section": "1.4.5: Network connections between trusted and untrusted networks are controlled.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.1", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the type configured in the rule parameter.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "1.5.1.2", "Description": "Checks if a Kubernetes Ingress resource has TLS configuration. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS secret for HTTPS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.5.1.3", "Description": "Checks if Kubernetes Services are associated with Network Policies. The rule is NON_COMPLIANT for a Kubernetes Service if it is not associated with a Network Policy.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.5.1.4", "Description": "Checks if Kubernetes Ingress resources are associated with a network policy. The rule is NON_COMPLIANT if an Ingress resource is not associated with a network policy.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.5.1.5", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default certificate. The rule is NON_COMPLIANT if an Ingress uses the default TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.5.1.6", "Description": "Checks if the Bitbucket source repository URL contains sign-in credentials. The status is NON_COMPLIANT if the URL contains any sign-in information and COMPLIANT if it doesn't.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "1.5.1.7", "Description": "Checks if Kubernetes services are of type LoadBalancer, as they can be publicly accessible. The rule is NON_COMPLIANT if the service type is LoadBalancer and it exposes the service to the public network.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.5.1.8", "Description": "Checks if Kubernetes persistent volumes are public. The rule is NON_COMPLIANT if any persistent volumes are accessible publicly without appropriate security measures.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.5.1.9", "Description": "Checks if the Kubernetes Network Policy permits traffic for all pods in the selected namespace. The policy is NON_COMPLIANT if 'ingress' rules allow traffic from all sources.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.5.1.10", "Description": "Checks if the status of the Kubernetes Deployment is 'AVAILABLE' or 'UNAVAILABLE' after the deployment process. The deployment is compliant if the status is 'AVAILABLE'.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "1.5.1.11", "Description": "Checks if Kubernetes Network Policies have 'allowExternal' enabled. The rule is NON_COMPLIANT for a Network Policy if 'allowExternal' is set to 'false'.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.5.1.12", "Description": "Checks if the Kubernetes API server endpoint is not publicly accessible. The rule is NON_COMPLIANT if the endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.5.1.13", "Description": "Checks if Kubernetes OpenSearch (Elasticsearch) instances are configured within a Kubernetes cluster. The rule is NON_COMPLIANT if an OpenSearch Service instance is exposed outside of the cluster.", - "Name": "Kubernetes OpenSearch (Elasticsearch)", + "Name": "Scheduler", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes OpenSearch (Elasticsearch)" + "Service": "Scheduler" } ] }, { "Id": "1.5.1.14", "Description": "Checks if Ingress resources in Kubernetes have TLS configured with certificates from a trusted certificate provider. This rule is NON_COMPLIANT if at least 1 Ingress has at least 1 TLS secret that is either missing or uses a certificate not issued by a trusted Certificate Authority.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "1.5.1.15", "Description": "Checks if Kubernetes Ingress Resources are configured to use TLS certificates provided by a Certificate Manager. To use this rule, ensure that TLS configuration is present in your Ingress Resource. This rule is only applicable to Kubernetes Ingress Resources and does not check other service types such as ClusterIP or NodePort.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "1.5.1.16", "Description": "Checks if a Kubernetes cluster has network policies that restrict public access. The rule is NON_COMPLIANT if NetworkPolicySpec.PodSelector does not restrict access to specific pods, or if it allows traffic on ports other than the specified secure ports (e.g., Port 22).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.17", "Description": "A Kubernetes Network Policy that restricts all incoming traffic to a pod, preventing SSH access from any external source, thus effectively disabling incoming SSH traffic.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.5.1.18", "Description": "Checks if network policies are applied to authorized namespaces in Kubernetes. The rule is NON_COMPLIANT if network policies are applied to unauthorized namespaces.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.19", "Description": "Checks if the Kubernetes PodSecurityPolicy attached to the Pod resource prohibits public access. If the PodSecurityPolicy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.20", "Description": "Checks if a Kubernetes Pod (representing a Lambda function) is allowed access to a Virtual Private Cloud (VPC). The rule is NON_COMPLIANT if the Pod is not configured to use a specific VPC network through Kubernetes Network Policies or specific annotations.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.21", "Description": "Checks if default ports for SSH/RDP ingress traffic for Kubernetes Network Policies are unrestricted. The rule is NON_COMPLIANT if a Network Policy allows an ingress traffic rule from any source CIDR block for ports 22 (SSH) or 3389 (RDP).", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "1.5.1.22", "Description": "Checks if a Kubernetes NetworkPolicy is configured with a user-defined action for fragmented packets. The rule is NON_COMPLIANT if the action for fragmented packets does not match the user-defined default action.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.5.1.23", "Description": "Check Kubernetes NetworkPolicy is associated with at least one ingress or egress rule. This rule is NON_COMPLIANT if no ingress or egress rules are associated with the NetworkPolicy else COMPLIANT if any one of the rule types exists.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.24", "Description": "Checks if a Kubernetes Network Policy contains ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined in the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.5.1.25", "Description": "Checks if there are public routes in the Kubernetes network configuration that allow external access. The rule is NON_COMPLIANT if a network policy allows all traffic to/from the pod(s) without restriction (similar to having a route to an IGW with a destination CIDR block of '0.0.0.0/0' or '::/0').", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.5.1.26", "Description": "Checks if Kubernetes clusters are deployed within a Virtual Private Cloud (VPC). The rule is NON_COMPLIANT if a Kubernetes service is exposed with a LoadBalancer type that allows public access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.27", "Description": "Checks if there are any Kubernetes Network Policies that are not the default Network Policy. The rule is NON_COMPLIANT if there are any Network Policies that are not the default Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.28", "Description": "Checks if the Kubernetes services are not exposed externally. The rule is NON_COMPLIANT if the type field of the service is set to 'LoadBalancer' or 'NodePort'.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.5.1.29", "Description": "Checks if Kubernetes services are not publicly accessible. The rule is NON_COMPLIANT if the service type is 'LoadBalancer' or 'NodePort' allowing external access.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "1.5.1.30", "Description": "Checks if Kubernetes services have network policies that prevent public access. The rule is NON_COMPLIANT if network policies are not configured to restrict public access to Kubernetes services.", - "Name": "Kubernetes Services", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Services" + "Service": "API Server" } ] }, { "Id": "1.5.1.31", "Description": "Verifies if the necessary public access settings for Kubernetes resources are configured at the cluster level. The status is marked as NON_COMPLIANT only when the specified security settings do not align with the expected configurations.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.32", "Description": "Verifies if the required network policies for ingress and egress traffic are configured for the Kubernetes cluster. The rule is NON_COMPLIANT if the network policy does not match one or more settings from parameters (or default).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.33", "Description": "Checks if Kubernetes Services are publicly accessible. The rule is NON_COMPLIANT if a Service type is LoadBalancer or NodePort and not listed in the excludedServices parameter.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.5.1.34", "Description": "Checks if your Kubernetes Cluster does not allow public access to sensitive services. The rule checks the Network Policies, the Service type (such as LoadBalancer or NodePort), and the RBAC permissions.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "1.5.1.35", "Description": "Checks if your Kubernetes persistent volumes do not allow public write access. The rule checks the PersistentVolumeClaim settings, the storage class, and the access modes of the persistent volumes.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "1.5.1.36", "Description": "Checks if a Kubernetes pod is deployed within a specific namespace or within a list of approved namespaces. The rule is NON_COMPLIANT if a pod is not deployed within the designated namespace or if its namespace is not included in the parameter list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.37", "Description": "Checks if direct internet access is disabled for a Kubernetes pod. The rule is NON_COMPLIANT if the pod has an outgoing IP address allowing internet access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.38", "Description": "Checks if a Kubernetes Service has Endpoints created for each associated Pod within the specified namespace. The state is NON_COMPLIANT if any Pod associated with the Kubernetes Service does not have an Endpoint created.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "1.5.1.39", "Description": "Checks if there are unused Network Policies. The rule is COMPLIANT if each Network Policy is associated with a Pod. The rule is NON_COMPLIANT if a Network Policy is not associated with a Pod.", - "Name": "Networking", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Networking" + "Service": "API Server" } ] }, { "Id": "1.5.1.40", "Description": "Verifies Kubernetes NetworkPolicies to ensure that unrestricted ingress connections (from '0.0.0.0/0') only allow inbound TCP or UDP traffic on specified ports. NetworkPolicies are considered NON_COMPLIANT if they do not define allowed ports in their specifications.", - "Name": "Kubernetes NetworkPolicies", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes NetworkPolicies" + "Service": "Core" } ] }, { "Id": "1.5.1.41", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.5.1.42", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The NetworkPolicy is NON_COMPLIANT if no rules are defined within it.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "1.5.1.43", "Description": "Checks whether a Kubernetes NetworkPolicy contains any ingress or egress rules. This rule is NON_COMPLIANT if a NetworkPolicy does not contain any ingress or egress rules.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "1.5.1.44", "Description": "Checks if Kubernetes Network Policies contain any rules. The rule is NON_COMPLIANT if there are no rules present within a Kubernetes Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "1.5.1.45", "Description": "Checks whether the Kubernetes Network Policy contains ingress or egress rules. This Network Policy is COMPLIANT if it defines at least one ingress or egress rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "1.5.1.46", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The rule is NON_COMPLIANT if there are no ingress or egress rules present within a NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "1.5.1: Risks to the CDE from computing devices that are able to connect to both untrusted networks and the CDE are mitigated.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLogSettings' is not present in Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logs enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the logging level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" - } - ] - }, - { - "Id": "10.2.1.1.3", - "Description": "Checks if Zephyr Tracing is enabled on Kubernetes Ingress Controllers. The rule is COMPLIANT if Zephyr Tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress Controller", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress Controller" - } - ] - }, - { - "Id": "10.2.1.1.4", - "Description": "Checks if an AWS AppSync API has logging enabled. The rule is NON_COMPLIANT if logging is not enabled, or 'fieldLogLevel' is neither ERROR nor ALL.", - "Name": "AWS AppSync", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "AWS AppSync" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.5", "Description": "Checks if Kubernetes Services are configured with the correct session affinity settings. The rule is NON_COMPLIANT if Service session affinity does not match the user-defined session affinity settings.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.2.1.1.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access requests to a designated logging system. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.7", "Description": "Checks if at least one Kubernetes Audit Policy is logging events for all pods. The rule is NON_COMPLIANT if there are no audit policies or if no policies record pod events.", - "Name": "Kubernetes Audit", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.8", "Description": "Checks if Kubernetes PodDisruptionBudgets (PDBs) have a policy configured for the desired states. Optionally verifies if any policies match a specified label selector. The rule is NON_COMPLIANT if there is no policy specified for the PDB or optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.1.9", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert for the named metric. For resource type, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource identifier and a corresponding Prometheus alert.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.1.10", - "Description": "The Kubernetes equivalent of monitoring for enabled CloudTrail in AWS can be likened to ensuring that auditing is enabled in the cluster, which tracks API calls and the actions performed on resources. This is critical for security and compliance purposes.", - "Name": "Kubernetes Audit Logging", - "Checks": [ - "apiserver_audit_log_path_set" - ], - "Attributes": [ - { - "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit Logging" + "Service": "Core" } ] }, { "Id": "10.2.1.1.11", "Description": "Checks if a Kubernetes Pod has at least one logging option enabled. The rule is NON_COMPLIANT if the status of all present logging configurations is set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.12", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes Cluster events. The rule is NON_COMPLIANT if logging is not enabled or logging for cluster events has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.13", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.14", "Description": "Checks if Kubernetes Cluster has audit logging enabled. The rule is NON_COMPLIANT if 'audit-log.enabled' is set to false.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.15", "Description": "Verifies whether the Kubernetes cluster has the necessary monitoring (such as Prometheus) enabled for its pods. The status is NON_COMPLIANT if monitoring is not properly configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.16", "Description": "Checks if log configuration is set on active Kubernetes Pods. This rule is NON_COMPLIANT if any active Pod does not have a valid logging configuration defined in its container specifications or if the logging configuration is null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.17", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for Kubernetes clusters is not enabled for all log types such as API server logs, audit logs, and etcd logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.18", "Description": "Checks if Kubernetes Pods are configured to send logs to a logging backend (e.g., Fluentd, Elasticsearch, or similar). The rule is NON_COMPLIANT if the logging configuration is not set up correctly or disabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.19", "Description": "Checks if the Kubernetes Ingress resource has access logging enabled with specified S3 bucket for logs. The rule is NON_COMPLIANT if the log configuration is not set or bucket does not match the specified S3 bucket name.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.20", "Description": "Checks if Kubernetes brokers have audit logging enabled. The rule is NON_COMPLIANT if a broker does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.21", "Description": "Checks if a Kubernetes pod has audit logging enabled. The rule is NON_COMPLIANT if the pod does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.22", "Description": "In Kubernetes, a similar rule could be the requirement to enable audit logging across multiple Kubernetes clusters located in different regions to ensure comprehensive tracking of user activities and resource access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.23", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.24", "Description": "Checks if Kubernetes Network Policies have logging enabled for traffic flow. The rule is NON_COMPLIANT if logging is not configured for any defined policy. You can specify which logging level or type you want the rule to check.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.2.1.1.25", "Description": "Checks if Kubernetes clusters have logging configured to send logs to an external logging service (e.g., Elasticsearch, Fluentd) for monitoring and auditing. The rule is NON_COMPLIANT if the clusters do not have log forwarding configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.26", "Description": "Checks if the respective logs of Kubernetes clusters are enabled. The rule is NON_COMPLIANT if any log types are not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.27", "Description": "Checks if Kubernetes clusters are logging audits to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.28", "Description": "Checks if Kubernetes clusters have the specified security settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using a configured network policy or if role-based access control (RBAC) is not properly enforced, or if audit logging is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.29", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS. The rule is NON_COMPLIANT if DNS query logging is not enabled for your Kubernetes cluster's CoreDNS.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.1.1.30", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.31", "Description": "Checks if Kubernetes Pod Security Standards are enforced for a namespace. The rule is NON_COMPLIANT if Pod Security Standards are not enforced.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.32", "Description": "Checks if Kubernetes Event logging is enabled for the delivery status of events sent to a resource for the endpoints. The rule is NON_COMPLIANT if the delivery status notification for events is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.33", "Description": "Checks if Kubernetes Audit Logging is enabled. The rule is NON_COMPLIANT if an audit logging configuration is not present or the logging level does not meet the minimum required level.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.34", "Description": "Checks if Kubernetes network policies are applied and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not applied to at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.1.35", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if logging is enabled but the log output destination does not match the specified configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.36", "Description": "Checks if the monitoring metrics collection on Kubernetes Network Policies is enabled. The rule is NON_COMPLIANT if the 'monitoringMetricsEnabled' field is set to false.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "10.2.1.1.37", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have logging enabled.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' annotation is not present in the Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.2", "Description": "Checks if all methods in Kubernetes Ingress have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if logging level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes API services. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes API Services", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Services" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or 'audit-log-path' is not set to a valid file path.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.5", "Description": "Checks if Kubernetes Services are configured with appropriate session affinity settings. The rule is NON_COMPLIANT if the session affinity settings do not match the user defined criteria for session persistence.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "10.2.1.2.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access to the backend services. The rule is NON_COMPLIANT if an Ingress resource does not have access logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.7", "Description": "Checks if at least one Kubernetes Audit Policy is logging API requests for all pods and namespaces. The rule is NON_COMPLIANT if there are no policies or if policies do not record pod and namespace API requests.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.2.8", - "Description": "The rule identifier CLOUD_TRAIL_ENABLED is equivalent to the Kubernetes configuration where a specific resource or service is monitored to ensure that CloudTrail is enabled for audit logging and security compliance.", - "Name": "CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CloudTrail" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.9", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism enabled (such as stdout/stderr logging or integration with a logging sidecar). The rule is NON_COMPLIANT if the logging configurations are all set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events. The rule is NON_COMPLIANT if logging is not enabled or the logging severity level for pod events is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.2.11", - "Description": "Checks if a Kubernetes MongoDB instance has logging enabled for audit logs. The rule is NON_COMPLIANT if the MongoDB instance does not have logging enabled for audit logs.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.12", "Description": "Checks if a Kubernetes cluster has logging enabled for its pods. The rule is NON_COMPLIANT if the pod spec 'spec.containers[].logConfig.enabled' is set to false.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.13", "Description": "Checks if logging is configured for active Kubernetes Pods and their associated Container definitions. This rule is NON_COMPLIANT if an active Pod does not have logging configured or if the logging configuration is absent in at least one Container specification.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types, such as container logs, audit logs, and application logs.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.15", "Description": "Checks if Kubernetes pods are configured to send logs to a logging backend (such as Fluentd or Elasticsearch). The rule is NON_COMPLIANT if the logging configuration does not send logs appropriately.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.16", "Description": "Checks if the Kubernetes Ingress and Service resources have access logging enabled. The rule is NON_COMPLIANT if the access logging is not configured or does not point to the specified log storage location (like a specific S3 bucket or object storage equivalent).", - "Name": "Ingress Controller (e.g., NGINX Ingress Controller)", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller (e.g., NGINX Ingress Controller)" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.17", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.18", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the Kubernetes audit logging is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.2.19", - "Description": "The rule identifier MULTI_REGION_CLOUD_TRAIL_ENABLED is different from the rule name multi-region-cloudtrail-enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.20", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policy" - } - ] - }, - { - "Id": "10.2.1.2.22", - "Description": "Checks if Amazon Aurora MySQL-Compatible Edition clusters are configured to publish audit logs to Amazon CloudWatch Logs. The rule is NON_COMPLIANT if Aurora MySQL-Compatible Edition clusters do not have audit log publishing configured.", - "Name": "Amazon Aurora", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Amazon Aurora" + "Service": "Core" } ] }, { "Id": "10.2.1.2.23", "Description": "Checks if respective logs of Kubernetes Pods are enabled. The rule is NON_COMPLIANT if any log types are not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.24", "Description": "Checks if Kubernetes clusters are logging audit events to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'auditLogDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using network policies, does not have role-based access control (RBAC) enabled, or if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes DNS services. The rule is NON_COMPLIANT if DNS query logging is not enabled for your Kubernetes DNS services.", - "Name": "Kubernetes DNS", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes DNS" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.27", "Description": "Checks if logging is enabled for your Kubernetes clusters. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.28", "Description": "Checks if a Kubernetes pod has logging enabled. The rule is NON_COMPLIANT if a pod does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.29", "Description": "Checks if Kubernetes Network Policies are defined and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not defined for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.2.30", "Description": "Checks if logging is enabled on Kubernetes Ingress controllers. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the expected configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource, if it does not have access logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' configuration is not specified in the Ingress resource.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes API services. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes API Services", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Services" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.4", "Description": "Checks if a Kubernetes Service has logging enabled. The rule is NON_COMPLIANT if logging is not enabled or if the log level is set to a value other than ERROR or ALL.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.5", "Description": "Checks if Kubernetes Services of type LoadBalancer are configured with a user-defined health check configuration. The rule is NON_COMPLIANT if the health check settings do not match the user-defined settings.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "Scheduler", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "Scheduler" } ] }, { "Id": "10.2.1.3.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access traffic to a specified logging service. The rule is NON_COMPLIANT if an Ingress resource does not have access logging enabled.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.7", "Description": "Checks if at least one Kubernetes Audit Policy is configured to log data access events for all Pods. The rule is NON_COMPLIANT if there are no policies or if no policies record data access events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.3.8", - "Description": "The Kubernetes equivalent for monitoring whether AWS CloudTrail is enabled, by checking if the relevant audit logging service is active in the cluster.", - "Name": "Kubernetes Audit Logging", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.9", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism enabled. The rule is NON_COMPLIANT if all present logging configurations are set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events in a target namespace. The rule is NON_COMPLIANT if logging is not enabled or pod event logging of a target namespace has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.11", "Description": "Checks if a Kubernetes cluster has logging enabled via a logging agent (like Fluentd) to export logs to a monitoring service (like Elasticsearch or CloudWatch) for audit purposes. The rule is NON_COMPLIANT if the Kubernetes cluster does not have log export enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.12", "Description": "Checks if the Kubernetes cluster has logging enabled for its pods. The rule is NON_COMPLIANT if 'spec.containers.logging' is set to false.", - "Name": "Kubernetes Cluster", + "Name": "Kubelet", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Cluster" + "Service": "Kubelet" } ] }, { "Id": "10.2.1.3.13", "Description": "Checks if log configuration is set on active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have logging configuration defined in its specification or the value for the logging configuration is null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for Kubernetes clusters is not enabled for all log types.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.15", "Description": "Checks if Kubernetes Pods are configured to send logs to a centralized logging solution (like Fluentd or Elasticsearch). The rule is NON_COMPLIANT if the logging configuration is not set to forward logs.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.16", "Description": "Checks if the Kubernetes Ingress and LoadBalancer services have logging enabled. The rule is NON_COMPLIANT if the ingress.annotations indicates logging is disabled or the configured log destination is not equal to the specified logging destination.", - "Name": "Ingress and LoadBalancer", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress and LoadBalancer" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.17", "Description": "Checks if Kubernetes clusters have auditing enabled. The rule is NON_COMPLIANT if audit logging is not enabled in the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.18", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled for the Kubernetes API server.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.3.19", - "Description": "The equivalence in Kubernetes relates to the configuration for enabling multi-region auditing across a cloud environment, similar to how 'MULTI_REGION_CLOUD_TRAIL_ENABLED' is utilized in AWS for CloudTrail logging in multiple regions. In Kubernetes, this can be associated with logging and monitoring across multiple clusters or namespaces, which may use tools such as Fluentd or Elasticsearch.", - "Name": "Kubernetes Logging", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Logging" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.20", "Description": "Checks if a Kubernetes cluster has logging enabled and if logs are being exported to an external logging service like Elasticsearch or a similar service. The rule is NON_COMPLIANT if logging is not enabled or if logs are not exported.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.21", "Description": "Checks if Kubernetes Network Policies are configured with appropriate logging. The rule is NON_COMPLIANT if a logging mechanism is not configured for traffic flow monitoring.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policy" - } - ] - }, - { - "Id": "10.2.1.3.22", - "Description": "Checks if Amazon Aurora MySQL-Compatible Edition clusters in Kubernetes are configured to publish audit logs to a centralized logging solution such as Fluentd, ELK Stack, or similar. The rule is NON_COMPLIANT if Aurora MySQL-Compatible Edition clusters do not have audit log publishing configured.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.23", "Description": "Checks if respective logs of Kubernetes are enabled. The rule is NON_COMPLIANT if any log types are not enabled, such as audit logs or container logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.24", "Description": "Checks if Kubernetes clusters have audit logging configured to send logs to a specific log aggregation service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logAggregationService' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using secrets for managing sensitive information or if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.2.1.3.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.1.3.27", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.28", "Description": "Checks if a Kubernetes Job has logging enabled. The rule is NON_COMPLIANT if a Job does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.29", "Description": "Checks if Kubernetes NetworkPolicy resources are defined and enforced for all namespaces. The rule is NON_COMPLIANT if NetworkPolicy is not defined for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.3.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if the logging is enabled but the logging destination does not match the specified value.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have access logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.3: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' annotation is not present in the Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if logging level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes services that expose APIs. The rule is COMPLIANT if OpenTelemetry tracing is enabled, and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "10.2.1.4.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or if 'auditLogPath' is not set or is set to an invalid log level.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.5", "Description": "Checks if Kubernetes Services of type LoadBalancer are configured with an appropriate externalTrafficPolicy. The rule is NON_COMPLIANT if the externalTrafficPolicy does not match the user-defined externalTrafficPolicy for preserving client source IP.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access to a specified logging service. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.7", "Description": "Checks if at least one Kubernetes Audit Policy is configured to log request and response data for all Pods in the cluster. The rule is NON_COMPLIANT if there are no audit policies or if none of the policies record Pod data events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.4.8", - "Description": "In Kubernetes, the equivalent of monitoring and ensuring that a specific service (CloudTrail) is enabled corresponds to implementing an Admission Controller that enforces policy checks on resource creation and modification, ensuring that necessary logging and monitoring (like AWS CloudTrail) is active. In this case, the rule identifier is akin to a specific policy or validation check, while the rule name can be considered as a user-friendly label for that check.", - "Name": "Admission Controller", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Admission Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.9", "Description": "Checks if a Kubernetes Pod's logging mechanism is properly configured. The rule is NON_COMPLIANT if all logging options (such as stdout/stderr or external logging solutions) are disabled.", - "Name": "Kubernetes Pod", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Pod" + "Service": "Core" } ] }, { "Id": "10.2.1.4.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes events of a target pod. The rule is NON_COMPLIANT if logging is not enabled or if pod logging has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4.11", "Description": "Checks if a Kubernetes cluster has the logging feature enabled for audit logs. The rule is NON_COMPLIANT if a Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.12", "Description": "Checks if Kubernetes Deployment has logging enabled for applications. The rule is NON_COMPLIANT if 'spec.template.spec.containers[0].env' does not contain a logging environment variable set to true.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "10.2.1.4.13", "Description": "Checks if logging is configured for active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have logging configured or the logging configuration is null for at least one container within the Pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types, such as application logs, audit logs, and kubelet logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.15", "Description": "Checks if Kubernetes clusters are configured to send logs to a logging solution (such as Fluentd or Elasticsearch) via log aggregation. The rule is NON_COMPLIANT if the logging agent is not properly configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4.16", "Description": "Checks if the Kubernetes Ingress has logging enabled. The rule is NON_COMPLIANT if the access logs are not directed to the specified log location or if the logging configuration is not enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" - } - ] - }, - { - "Id": "10.2.1.4.17", - "Description": "Checks if Kafka brokers deployed in a Kubernetes cluster have logging enabled. The rule is NON_COMPLIANT if a broker does not have logging enabled.", - "Name": "Kafka", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kafka" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.18", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.4.19", - "Description": "In Kubernetes, this rule indicates that a specific resource or controller must be configured to enable functionality across multiple regions, similar to Multi-Region CloudTrail in AWS, ensuring that events are captured from all regions in a centralized manner.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.20", "Description": "Checks if a Kubernetes cluster has logging enabled with a centralized logging solution, such as Elasticsearch, Fluentd, and Kibana (EFK) or Loki, for audit logs. The rule is NON_COMPLIANT if logging is not enabled for audit logs in the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.21", "Description": "Checks if the Kubernetes Network Policy logs are enabled. The rule is NON_COMPLIANT if logging is not configured for the specified Network Policy types.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.2.1.4.22", "Description": "Checks if Kubernetes clusters are configured to send audit logs to a logging service like Fluentd or ElasticSearch. The rule is NON_COMPLIANT if Kubernetes clusters do not have audit log publishing configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.23", "Description": "Checks if respective logs of Kubernetes are enabled. The rule is NON_COMPLIANT if any log types are not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.4.24", - "Description": "Checks if Amazon EKS clusters are logging audits to a specific cloud storage. The rule is NON_COMPLIANT if audit logging is not enabled for an EKS cluster or if the 'bucketNames' parameter is provided but the audit logging destination does not match.", - "Name": "Amazon EKS", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Amazon EKS" + "Service": "Core" } ] }, { "Id": "10.2.1.4.25", "Description": "Checks if Kubernetes clusters have the specified security settings. The rule is NON_COMPLIANT if the Kubernetes cluster does not have encryption enabled for secrets or uses an invalid encryption key, or if the cluster does not have auditing enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.2.1.4.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS in the Kubernetes cluster.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.1.4.27", "Description": "Checks if logging is enabled for your Kubernetes pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4.28", "Description": "Checks if Kubernetes Pods have logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging enabled or the logging configuration is not at the minimum level required.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4.29", "Description": "Checks if Kubernetes network policies are enforced and configured for all namespaces. The rule is NON_COMPLIANT if network policies are not defined for at least one namespace.", - "Name": "Kubernetes Network Policies", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policies" + "Service": "Core" } ] }, { "Id": "10.2.1.4.30", "Description": "Checks if logging is enabled on Kubernetes Ingress controllers. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the expected configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.4.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have access logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.4: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLogs' settings are not present in the Ingress configuration.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.2", "Description": "Checks if all methods in Kubernetes Ingress have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress resources. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or if 'logLevel' is neither 'Error' nor 'All'.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.5", "Description": "Checks if Kubernetes Services are configured with a user-defined session affinity setting. The rule is NON_COMPLIANT if the service session affinity does not match the user-defined session affinity mode.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.2.1.5.6", "Description": "Checks if Kubernetes Ingress resources are configured to log requests to a specified logging service. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.7", "Description": "Checks if at least one Kubernetes audit policy is configured to log API requests for all namespaces. The rule is NON_COMPLIANT if there are no audit policies or if existing policies do not log API requests.", - "Name": "Kubernetes Audit", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit" - } - ] - }, - { - "Id": "10.2.1.5.8", - "Description": "The rule identifier CLOUD_TRAIL_ENABLED corresponds to the rule name cloudtrail-enabled in Kubernetes, indicating that it is used to verify if AWS CloudTrail is enabled for monitoring and logging API calls.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "AWS CloudTrail" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.9", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism configured. The rule is NON_COMPLIANT if the status of all present logging configurations is set to 'DISABLED'.", - "Name": "Kubernetes Pod", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Pod" + "Service": "Core" } ] }, { "Id": "10.2.1.5.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes Pod events. The rule is NON_COMPLIANT if logging is not enabled or Pod logging has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.11", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if a Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.12", "Description": "Checks if Kubernetes has client connection logging enabled for its API server. The rule is NON_COMPLIANT if the 'audit-log.enabled' setting is set to false.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.13", "Description": "Checks if log settings are defined in active Kubernetes Pod specifications. This rule is NON_COMPLIANT if an active Pod does not have the logging configuration defined or the value for logging is null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.15", "Description": "Checks if Kubernetes Pods are configured to send logs to a central logging solution (e.g., Fluentd, Elasticsearch, or others). The rule is NON_COMPLIANT if the logging agent is not deployed or configured incorrectly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.16", "Description": "Checks if the Ingress Resource has access logging enabled. The rule is NON_COMPLIANT if the annotations for access logs are not set correctly or do not match the specified S3 bucket name.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.17", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.18", "Description": "Checks if a Kubernetes pod has audit logging enabled. The rule is NON_COMPLIANT if the pod does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.5.19", - "Description": "The rule identifier is MULTI_REGION_CLOUD_TRAIL_ENABLED, while the rule name is represented as multi-region-cloudtrail-enabled, indicating a distinction between the two in resource management.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "AWS CloudTrail" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.20", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if a Kubernetes cluster does not have audit log export enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.22", "Description": "Checks if Kubernetes clusters are configured to log audit events to a logging solution. The rule is NON_COMPLIANT if Kubernetes clusters do not have audit logging configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.23", "Description": "Checks if the respective logs of Kubernetes pods are enabled. The rule is NON_COMPLIANT if any log settings for the pods are not configured correctly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.24", "Description": "Checks if Kubernetes pods are logging audits to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a pod or if the 'logDestination' parameter is provided but the logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not encrypted or uses a different encryption key, or if the cluster does not have auditing enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster Ingress resources. The rule is NON_COMPLIANT if DNS query logging is not enabled for your Ingress resources.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.27", "Description": "Checks if logging is enabled for your Kubernetes cluster resources. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.28", "Description": "Checks if a Kubernetes Job has logging enabled. The rule is NON_COMPLIANT if a Job does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes Job", + "Name": "Kubelet", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Job" + "Service": "Kubelet" } ] }, { "Id": "10.2.1.5.29", "Description": "Checks if Kubernetes Network Policies are configured and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not enforced for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.5.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if the logging is enabled but the logging destination does not match the expected value.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.5.31", "Description": "Checks if logging is enabled on the Kubernetes Ingress resource. The Ingress is considered NON_COMPLIANT if it does not have logging enabled for traffic monitoring.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.5: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'access-log' annotation is not present in the Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress resources. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.4", "Description": "Checks if a Kubernetes API has logging enabled. The rule is NON_COMPLIANT if logging is not enabled, or if the log level is neither ERROR nor ALL.", - "Name": "Kubernetes API", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.5", "Description": "Checks if Kubernetes Services are configured with a specific Session Affinity setting. The rule is NON_COMPLIANT if the Service's Session Affinity does not match the user defined Session Affinity setting.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.2.1.6.6", "Description": "Checks if Kubernetes services have access logging configured to an external logging system. The rule is NON_COMPLIANT if a Kubernetes service does not have logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.7", "Description": "Checks if at least one Kubernetes Audit Policy is configured to record 'Read' events for all PersistentVolumeClaims (PVCs). The rule is NON_COMPLIANT if there are no Audit Policies that record 'Read' events for PVCs.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.6.8", - "Description": "The equivalence in Kubernetes for enabling CloudTrail in AWS is similar to ensuring that audit logging is enabled for security monitoring in Kubernetes. This can be achieved by configuring the audit logging settings in the Kubernetes API server.", - "Name": "Kubernetes", - "Checks": [ - "apiserver_audit_log_path_set" - ], - "Attributes": [ - { - "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.2.1.6.9", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism enabled. The rule is NON_COMPLIANT if there are no logging configurations set for the Pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes deployment events. The rule is NON_COMPLIANT if logging is not enabled or deployment logging has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.11", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.12", "Description": "Checks if the Kubernetes Cluster has logging enabled for client connections to the API server. The rule is NON_COMPLIANT if 'apiServer.clientConnectionLogging' is set to false.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.13", "Description": "Checks if the logging configuration is set on active Kubernetes Pod specifications. This rule is NON_COMPLIANT if an active Pod does not have a logging configuration defined or if the value for logging is null in at least one container specification.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled for all log types (e.g., audit logs, application logs). The rule is NON_COMPLIANT if logging is not enabled for all types in the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.15", "Description": "Checks if Kubernetes Pods are configured to send logs to a centralized logging service. The rule is NON_COMPLIANT if the value of 'log-driver' is not set to 'fluentd' or 'json-file'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.16", "Description": "Checks if the Kubernetes Ingress and Service resources have logging enabled. The rule is NON_COMPLIANT if the access logs are not configured to store logs in a specified logging backend, or if the logging backend does not match the required configuration.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.17", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.18", "Description": "Checks if a Kubernetes pod has audit logging enabled. The rule is NON_COMPLIANT if the pod does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.6.19", - "Description": "The rule identifier 'MULTI_REGION_CLOUD_TRAIL_ENABLED' corresponds to the Kubernetes equivalent of enabling multi-region logging for a CloudTrail service, reflecting compliance and enhanced observability of resources across multiple regions.", - "Name": "CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CloudTrail" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.20", "Description": "Checks if a Kubernetes database (such as PostgreSQL) cluster has logging enabled to a logging service (e.g., Fluentd, Elasticsearch) for auditing purposes. The rule is NON_COMPLIANT if the database cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.21", "Description": "Checks if Kubernetes NetworkPolicies have logging enabled. The rule is NON_COMPLIANT if no logging configuration is specified for the NetworkPolicy. You can specify which logging type to check for, such as audit logging or other logging mechanisms.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.22", "Description": "Checks if Kubernetes clusters have audit logging configured to output logs to a specified location. The rule is NON_COMPLIANT if Kubernetes clusters do not have audit log publishing configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.6.23", - "Description": "Checks if the logging is enabled for the respective Kubernetes Pods or StatefulSets. The rule is NON_COMPLIANT if any log types are not enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.24", "Description": "Checks if Kubernetes clusters are logging audits to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if a specific 'loggingDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster does not have encryption enabled for secrets or if it is using an insecure storage backend, or if an audit logging mechanism is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.1.6.27", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.28", "Description": "Checks if Kubernetes Pods have logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging enabled or the logging configuration is not at the minimum level specified.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.29", "Description": "Checks if Kubernetes Network Policies are implemented and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not enforced for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.6.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the specified parameter value.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.6.31", "Description": "Checks if logging is enabled on Kubernetes Ingress controllers. The rule is NON_COMPLIANT for an Ingress resource if it does not have logging enabled.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.6: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'access-log' annotation is not present in the Ingress configuration.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the logging level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.3", "Description": "Checks if OpenTelemetry tracing is enabled for Kubernetes Ingress resources. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.4", "Description": "Checks if a Kubernetes cluster has logging enabled for its pods. The rule is NON_COMPLIANT if logging is not configured, or the log level is neither ERROR nor ALL.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.5", "Description": "Checks if Kubernetes Services are configured with a user-defined session affinity mode. The rule is NON_COMPLIANT if the Service's session affinity mode does not match the user-defined session affinity mode.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "10.2.1.7.6", "Description": "Checks if Kubernetes Ingress resources are configured to enable access logging to a designated storage backend. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.7", "Description": "Checks if at least one Kubernetes audit policy is configured to log all requests to all pods and services. The rule is NON_COMPLIANT if there are no audit policies or if they do not record requests to all resources.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.7.8", - "Description": "In Kubernetes, the equivalence for monitoring and ensuring that a specific service is enabled, akin to checking if AWS CloudTrail is enabled, can be represented by monitoring the existence of a specific Deployment or Service that ensures logging and auditing is being executed correctly. Similar to the AWS rule, this would involve verifying configurations or custom resources that ensure that logging is enabled within the cluster.", - "Name": "Kubernetes Logging (e.g., Fluentd, Elasticsearch)", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Logging (e.g., Fluentd, Elasticsearch)" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.9", "Description": "Checks if a Kubernetes Pod has at least one logging configuration enabled. The rule is NON_COMPLIANT if the status of all present logging configurations is set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events associated with a target application. The rule is NON_COMPLIANT if logging is not enabled or pod logging severity level for the target application is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.7.11", - "Description": "Checks if a MongoDB instance running on Kubernetes has logging enabled to a monitoring solution (like Prometheus) for audit logs. The rule is NON_COMPLIANT if the MongoDB instance does not have logging enabled for audit logs.", - "Name": "MongoDB on Kubernetes", - "Checks": [ - "apiserver_audit_log_path_set" - ], - "Attributes": [ - { - "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "MongoDB on Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.12", "Description": "Checks if the Kubernetes Cluster has logging enabled for connections to services. The rule is NON_COMPLIANT if 'logging.configuration.enabled' is set to false.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.13", "Description": "Checks if logConfiguration is set on active Kubernetes Pod specifications. This rule is NON_COMPLIANT if an active Pod does not have a logging configuration specified or if the logging configuration is null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types, including audit logs, application logs, and any other relevant log types.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.15", "Description": "Checks if Kubernetes clusters are configured to send logs to a centralized logging service like Elasticsearch or a monitoring tool like Prometheus. The rule is NON_COMPLIANT if logging is not properly configured or if logs are not being collected.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.16", "Description": "Checks if the Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if the access logging is not configured or if the configured logging destination does not match the specified S3 bucket name.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.17", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.18", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.7.19", - "Description": "The Kubernetes equivalent for cloud resource monitoring with a focus on enabling multi-region logging, akin to enabling CloudTrail for multiple regions in AWS.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.20", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policies" - } - ] - }, - { - "Id": "10.2.1.7.22", - "Description": "Checks if Amazon Aurora MySQL-Compatible Edition clusters are configured to publish audit logs to Amazon CloudWatch Logs. The rule is NON_COMPLIANT if Aurora MySQL-Compatible Edition clusters do not have audit log publishing configured.", - "Name": "Amazon Aurora", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Amazon Aurora" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.23", "Description": "Checks if the respective logs of Kubernetes pods are enabled. The rule is NON_COMPLIANT if any log types are not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.24", "Description": "Checks if Kubernetes clusters are auditing logs to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using Role-Based Access Control (RBAC) or if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.26", "Description": "Checks if DNS logging is enabled for your Kubernetes cluster's CoreDNS or kube-dns configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled for the DNS service in the cluster.", - "Name": "CoreDNS / kube-dns", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS / kube-dns" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.27", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "10.2.1.7.28", "Description": "Checks if Kubernetes workloads have logging enabled. The rule is NON_COMPLIANT if a workload does not have logging enabled or the logging configuration does not meet the minimum specified requirements.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.29", "Description": "Checks if Kubernetes Network Policies are configured and applied for all namespaces. The rule is NON_COMPLIANT if network policies are not applied in at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.7.30", "Description": "Checks if logging is enabled on Kubernetes Network Policies. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the expected values.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "10.2.1.7.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1.7: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' annotation is not present in Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.2", "Description": "Checks if all methods in Kubernetes Ingress resources have logging enabled. The rule is NON_COMPLIANT if logging is not enabled or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes services. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or the audit policy does not include both 'metadata' and 'requestBodies' logs.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.1.5", "Description": "Checks if Kubernetes Ingress controllers are configured with appropriate desynchronization mitigation settings as per user-defined requirements. The rule is NON_COMPLIANT if the Ingress desync mitigation settings do not match user-defined configurations.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access details. The rule is NON_COMPLIANT if an Ingress resource does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.7", "Description": "Checks if at least one Kubernetes Audit Policy is logging access events for all Pods in the cluster. The rule is NON_COMPLIANT if there are no audit records for Pod access events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.8", - "Description": "The Kubernetes equivalent involves ensuring that logs and events are being recorded properly, similar to how AWS CloudTrail captures API activity. This can be achieved by enabling logging features on the Kubernetes cluster, particularly through mechanisms like audit logging and monitoring tools.", - "Name": "Kubernetes Audit Logging", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "10.2.1.9", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism enabled. The rule is NON_COMPLIANT if the status of all present logging configurations (such as logging to stdout/stderr or using a sidecar for logging) is set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events of a target application. The rule is NON_COMPLIANT if logging is not enabled or pod logging of a target application has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.11", - "Description": "Checks if a MongoDB instance running on Kubernetes has logging enabled to a specified logging service. The rule is NON_COMPLIANT if the MongoDB instance does not have logging enabled.", - "Name": "MongoDB on Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "MongoDB on Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.12", "Description": "Checks if Kubernetes cluster has logging for connections to services enabled. The rule is NON_COMPLIANT if 'service.spec.sessionAffinity' is not set to 'ClientIP'.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "10.2.1.13", "Description": "Checks if the logging configuration is set on active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have logging configuration defined or the value for the logging configuration is null in at least one container within the Pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types such as audit logs, application logs, and system logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.15", "Description": "Checks if Kubernetes applications are configured to send logs to a logging solution like Fluentd or ELK Stack. The rule is NON_COMPLIANT if the logging configuration is not set up properly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.16", "Description": "Checks if the Kubernetes LoadBalancer service has logging enabled. The rule is NON_COMPLIANT if the service annotations for external-dns are not set correctly or if the S3 bucket for logs is not properly configured.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "Scheduler", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "Scheduler" } ] }, { "Id": "10.2.1.17", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.18", "Description": "Checks if a Kubernetes cluster has auditing enabled. The rule is NON_COMPLIANT if auditing is not configured properly.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.1.19", - "Description": "In Kubernetes, the equivalent concept to monitoring policies like 'MULTI_REGION_CLOUD_TRAIL_ENABLED' can be represented as a 'Policy' or 'Rule', which defines the configurations and behaviors needed for a multi-cluster environment spread across different regions. The rule name ('multi-region-cloudtrail-enabled') is how it's referenced in specific configurations, while the identifier ('MULTI_REGION_CLOUD_TRAIL_ENABLED') serves as a unique key for programmatic access and management.", - "Name": "Kubernetes Policy Management", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Policy Management" + "Service": "API Server" } ] }, { "Id": "10.2.1.20", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.1.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policy" - } - ] - }, - { - "Id": "10.2.1.22", - "Description": "Checks if Amazon Aurora MySQL-Compatible Edition clusters are configured to publish audit logs to Amazon CloudWatch Logs. The rule is NON_COMPLIANT if Aurora MySQL-Compatible Edition clusters do not have audit log publishing configured.", - "Name": "Amazon Aurora MySQL-Compatible Edition", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Amazon Aurora MySQL-Compatible Edition" + "Service": "Core" } ] }, { "Id": "10.2.1.23", "Description": "Checks if respective logs of Kubernetes Pods are enabled. The rule is NON_COMPLIANT if any logs related to the application are not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.24", "Description": "Checks if Kubernetes Pods are logging events to a specific logging service. The rule is NON_COMPLIANT if logging is not enabled for a Pod or if the 'logDestination' parameter is provided but the logging service does not match.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster does not have Secrets encryption enabled or uses an insecure key, or if audit logging is not enabled for the cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.26", "Description": "Checks if DNS query logging is enabled for Kubernetes services using CoreDNS. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS in your Kubernetes cluster.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.1.27", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -6849,1192 +6495,1120 @@ { "Id": "10.2.1.29", "Description": "Checks if Kubernetes Network Policies are configured and enforced for all namespaces. The rule is NON_COMPLIANT if Network Policies are not configured for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.1.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if the logging is enabled but the logging destination does not match the expected configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.1.31", "Description": "Checks if logging is enabled for Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have access logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.1: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.2.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging annotations are not present in the Ingress resource configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.2.2", "Description": "Checks if all methods in Kubernetes Ingress have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.2.3", "Description": "Checks if OpenTelemetry tracing is enabled for Kubernetes services. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not configured or 'audit-log-path' does not have a valid path set.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.2.5", "Description": "Checks if Kubernetes Services are configured with appropriate LoadBalancer settings. The rule is NON_COMPLIANT if the Service's LoadBalancer settings do not match the user-defined configurations for handling desynchronization scenarios.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.2.2.6", "Description": "Checks if Kubernetes Ingress resources are configured to enable access logging. The rule is NON_COMPLIANT if an Ingress resource does not have access logging configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.7", "Description": "Checks if at least one Kubernetes Audit Policy is configured to log access to all Pods in the cluster. The rule is NON_COMPLIANT if there are no audit policies or if no policies log Pod access events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.2.2.8", - "Description": "The rule identifier CLOUD_TRAIL_ENABLED relates to ensuring that AWS CloudTrail is enabled for monitoring API calls, while its equivalent in Kubernetes could be ensuring that audit logging is enabled for monitoring API requests within the Kubernetes cluster. This helps maintain security and compliance by tracking changes and access in the cluster.", - "Name": "Kubernetes Audit Logging", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "10.2.2.9", "Description": "Checks if a Kubernetes Pod has at least one logging option enabled. The rule is NON_COMPLIANT if the status of all present logging configurations is set to 'DISABLED'.", - "Name": "Kubernetes Pod Logging", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Pod Logging" + "Service": "Core" } ] }, { "Id": "10.2.2.10", "Description": "Checks if logging is enabled with a valid severity level for a Kubernetes Deployment's application logs. The rule is NON_COMPLIANT if logging is not enabled or application logging has a severity level that is not valid.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "10.2.2.11", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.12", "Description": "Checks if Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if 'audit-log-path' is set to an empty value or audit logging is not configured.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.2.2.13", "Description": "Checks if logging is configured for active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have logging configured, or the value for logging is null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.14", "Description": "Checks if a Kubernetes cluster has logging enabled for all log types, such as audit logs, application logs, and cluster logs. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.15", "Description": "Checks if Kubernetes Pods are configured to send logs to a centralized logging system (e.g., Fluentd or Elasticsearch). The rule is NON_COMPLIANT if the logging driver or configuration is not set to forward logs.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.16", "Description": "Checks if the Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if the access logging is not configured correctly or pointing to the specified S3 bucket for log storage.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.2.2.17", "Description": "Checks if Kubernetes brokers (such as those created with Strimzi or similar tools) have logging enabled for auditing (e.g., using Fluentd, Elasticsearch, and Kibana). The rule is NON_COMPLIANT if a broker does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.18", "Description": "Checks if a Kubernetes pod has audit logging enabled. The rule is NON_COMPLIANT if the pod does not have audit logging enabled.", - "Name": "Kubernetes Pod", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Pod" - } - ] - }, - { - "Id": "10.2.2.19", - "Description": "In Kubernetes, a valid equivalent for monitoring multi-region cloud activities can be achieved by using Cross-Cluster Services or utilizing Kubernetes' built-in audit logging mechanisms to track operations across multiple clusters in different regions.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.20", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if a Kubernetes cluster does not have logging enabled for audit logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured for traffic policies. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Network Policies" - } - ] - }, - { - "Id": "10.2.2.22", - "Description": "In Kubernetes, ensure that your MySQL database (Deployed using a StatefulSet or similar) is configured to log queries or audit logs and send those logs to a logging solution like Elasticsearch, Fluentd, or a similar service integrated with CloudWatch. The rule is NON_COMPLIANT if MySQL clusters do not have appropriate logging or auditing configured.", - "Name": "MySQL StatefulSet", - "Checks": [], - "Attributes": [ - { - "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "MySQL StatefulSet" + "Service": "API Server" } ] }, { "Id": "10.2.2.23", "Description": "Checks if the respective logs of the Kubernetes cluster (such as auditing, application logs, or container logs) are enabled. The rule is NON_COMPLIANT if any logging mechanisms are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.24", "Description": "Checks if Kubernetes clusters are logging audits to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.2.2.25", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster does not have encryption for etcd enabled, or if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, { "Id": "10.2.2.26", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configurations. The rule is NON_COMPLIANT if DNS query logging is not enabled for the CoreDNS service associated with the cluster's ingress traffic management.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.2.2.27", "Description": "Checks if logging is enabled for your Kubernetes clusters. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.28", "Description": "Checks if a Kubernetes Pod has logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.29", "Description": "Checks if Kubernetes Network Policies are configured and enforced for all namespaces. The rule is NON_COMPLIANT if Network Policies are not enabled for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.2.2.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the specified configuration.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.2.2.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource, if it does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.2.2: Audit logs are implemented to support the detection of anomalies and suspicious activity, and the forensic analysis of events.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging configuration is not defined in the Ingress resource annotations.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if logging is not enabled, or if log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress controllers. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or 'audit.log.level' is neither 'ERROR' nor 'ALL'.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.3.1.5", "Description": "Checks if Kubernetes Services that use LoadBalancer type are configured with a user-defined externalTrafficPolicy. The rule is NON_COMPLIANT if the externalTrafficPolicy does not match the user-defined externalTrafficPolicy.", - "Name": "Kubernetes Services", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Services" + "Service": "API Server" } ] }, { "Id": "10.3.1.6", "Description": "Checks if Kubernetes Ingress resources are configured to enable access logging to a specified logging service (e.g., Fluentd or a centralized logging system). The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.7", "Description": "Checks if at least one Kubernetes Audit Policy is enforcing the logging of access events for all pods in the cluster. The rule is NON_COMPLIANT if there are no audit logs or if the audit policies do not record access events for pods.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.8", "Description": "The Kubernetes equivalent of enabling CloudTrail would be to ensure that logging and monitoring services are set up for tracking user activity and changes within the cluster. This typically involves using tools like Fluentd, Elasticsearch, Kibana (the EFK stack), or Kubernetes' built-in audit logging.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.9", "Description": "Checks if a Kubernetes Pod has at least one logging option enabled. The rule is NON_COMPLIANT if the status of all present log configurations is set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.10", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events. The rule is NON_COMPLIANT if logging is not enabled or pod event logging has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.1.11", - "Description": "Checks if a Kubernetes MongoDB instance running on a cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if a MongoDB instance in the Kubernetes cluster does not have auditing logs enabled.", - "Name": "MongoDB on Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "MongoDB on Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.12", "Description": "Checks if the Kubernetes cluster has client connection logging enabled in the Ingress controller. The status is NON_COMPLIANT if 'clientLogging.enabled' is set to false.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "10.3.1.13", "Description": "Checks if logging is configured for active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have a logging configuration set or the logging configuration is null in at least one container specification.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.14", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes cluster is not enabled for all log types, such as audit logs, application logs, and container logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.15", "Description": "Checks if Kubernetes pods are configured to send logs to a centralized logging system (like Fluentd, ELK stack, or any other log management solution). The rule is NON_COMPLIANT if the logging configuration does not forward logs to the configured logging system.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.16", "Description": "Checks if the Kubernetes Service of type LoadBalancer has logging enabled. The rule is NON_COMPLIANT if the service does not have an annotation for logging enabled or the designated logging namespace does not match the expected value.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.3.1.17", "Description": "Checks if Kubernetes Pods have auditing enabled. The rule is NON_COMPLIANT if a Pod does not have auditing enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.18", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the audit logging is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.1.19", - "Description": "The multi-region-cloudtrail-enabled rule ensures that AWS CloudTrail is enabled across multiple regions, providing enhanced visibility and security for resource activity in the cloud environment.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "AWS CloudTrail" + "Service": "API Server" } ] }, { "Id": "10.3.1.20", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.21", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if logging is not configured for the Network Policies. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "10.3.1.22", "Description": "Checks if Kubernetes clusters are configured to log audit events to a specified logging solution. The rule is NON_COMPLIANT if Kubernetes clusters do not have audit logging configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.23", "Description": "Checks if the necessary logging is enabled for the Kubernetes cluster and its components. The rule is NON_COMPLIANT if any required log types, such as audit logs or application logs, are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.24", "Description": "Checks if Kubernetes clusters are logging audits to a specific logging service. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the specified logging destination does not match the expected service.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.1.25", "Description": "Checks if Kubernetes clusters have the specified security settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using encryption for secrets or configurations, or if audit logging is not enabled for the cluster.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.1.26", "Description": "Checks if CoreDNS logging is enabled for your Kubernetes cluster. The rule is NON_COMPLIANT if CoreDNS logging is not enabled for your Kubernetes cluster.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.3.1.27", "Description": "Checks if logging is enabled for your Kubernetes pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.1.28", - "Description": "Checks if Kubernetes StatefulSet has logging enabled. The rule is NON_COMPLIANT if a StatefulSet does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes StatefulSet", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes StatefulSet" + "Service": "Core" } ] }, { "Id": "10.3.1.29", "Description": "Checks if Kubernetes Network Policies are defined and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not configured for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.1.30", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the expected destination parameter.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.1.31", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource, if it does not have logging enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.1: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.2.1", "Description": "Checks if a Kubernetes namespace has an associated Network Policy that prevents pod egress. The rule is NON_COMPLIANT if the namespace does not have network policies or has policies that do not include appropriate deny rules for egress traffic (rules that restrict access to external services).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.2.2", "Description": "Checks that there is at least one Kubernetes Audit Policy defined with security best practices. This rule is COMPLIANT if there is at least one audit policy that meets all of the following:", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.3", "Description": "Checks if Kubernetes secrets are encrypted at rest using a specified encryption provider configuration. The rule is NON_COMPLIANT if a secret is not encrypted or is encrypted with a key not specified in the rule parameters.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.4", "Description": "Checks if Kubernetes Secrets are configured to use encryption at rest. The rule is COMPLIANT if the encryption configuration is defined in the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.5", "Description": "Checks if Kubernetes audit logging is enabled and configured properly. It is recommended that audit logging is enabled for all clusters to ensure logs are validated for compliance. The rule is NON_COMPLIANT if audit logging is not enabled or misconfigured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.6", "Description": "Checks if Kubernetes Services are exposed publicly. The rule is NON_COMPLIANT if the service type is set to LoadBalancer or if the service has an External IP.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "10.3.2.7", "Description": "Checks if Kubernetes PersistentVolume (PV) snapshots are public. The rule is NON_COMPLIANT if any Kubernetes PersistentVolume snapshots are public.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.8", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are not publicly accessible. The rule is NON_COMPLIANT if one or more Persistent Volumes have the accessModes field set to 'ReadWriteMany' allowing multiple pods (potentially from different namespaces) to access the volume, making it publicly accessible.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.9", "Description": "Checks if Kubernetes Pods have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the Pod's security context is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.2.10", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are configured to enforce a specific mount path. The rule is NON_COMPLIANT if the value of 'mountPath' is set to '/' (default root directory).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.11", "Description": "Checks if Kubernetes persistent volume claims (PVC) access modes are configured to enforce a user identity. The rule is NON_COMPLIANT if access modes do not enforce the required security context or if parameters provided in the PVC do not match the expected configuration.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.12", "Description": "Checks if a Kubernetes cluster has public access settings correctly configured for its services. The rule is NON_COMPLIANT if 'AllowExternalAccess' is set to true and there are services exposed to the public via LoadBalancer or NodePort types, except for port 22.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.13", "Description": "Checks if the Kubernetes Service policy attached to the Service resource prohibits public access. If the Service policy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.3.2.14", "Description": "Checks if a Kubernetes persistent volume is publicly accessible. The rule is NON_COMPLIANT if any existing or new persistent volume is exposed to the public.", - "Name": "Kubernetes Persistent Volumes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Persistent Volumes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.15", "Description": "Checks if the Kubernetes database service (e.g., PostgreSQL, MySQL) instances are not exposed to the external network. The rule is NON_COMPLIANT if the service type is 'LoadBalancer' or if there's an ingress route allowing external traffic.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.3.2.16", "Description": "Checks if Kubernetes Persistent Volume (PV) claims are publicly accessible. The rule is NON_COMPLIANT if any existing and new Persistent Volumes are configured inappropriately, allowing public access.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.17", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the cluster's LoadBalancer service has an external IP configured, allowing public access.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.18", "Description": "Checks if Kubernetes services have network policies that restrict public access. The rule is NON_COMPLIANT if network policies are not enforced for services that are exposed to the public.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "10.3.2.19", "Description": "Checks if the required network policies are configured to restrict public access to Kubernetes services. The rule is only NON_COMPLIANT when the network policy settings do not align with the expected configuration.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.3.2.20", "Description": "Checks if the required Network Policies for public access are configured at the namespace level. The rule is NON_COMPLIANT if the Network Policies do not match one or more settings from parameters (or default).", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.3.2.21", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a service is not listed in the excludedPublicServices parameter and service type is 'LoadBalancer' or has a public IP.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.2.22", "Description": "Checks if two-factor authentication (2FA) is enabled for Kubernetes secrets management. The rule is NON_COMPLIANT if 2FA is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.2.23", "Description": "Checks if your Kubernetes storage classes do not allow public access. The rule checks the security context, role-based access control (RBAC) settings, and the PersistentVolumeClaims (PVCs) configurations.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.24", "Description": "Checks if your Kubernetes Persistent Volume Claims (PVCs) do not allow public write access. The rule evaluates the Access Modes settings, the Persistent Volume (PV) policies, and any associated Role-Based Access Control (RBAC) configurations.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.2.25", "Description": "Checks if direct internet access is disabled for a Kubernetes Pod. The rule is NON_COMPLIANT if a Pod is configured with Internet access through a NetworkPolicy that allows external traffic.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.2.26", "Description": "Checks if Kubernetes ConfigMaps owned by the namespace are accessible publicly. The rule is NON_COMPLIANT if ConfigMaps with the owner 'Self' are exposed to external traffic.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.3.2: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.3.1", "Description": "Checks if Kubernetes database instances (such as PostgreSQL or MySQL running on Kubernetes) are protected by a backup plan. The rule is NON_COMPLIANT if the database instance is not protected by a backup plan.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -8065,80 +7639,68 @@ { "Id": "10.3.3.4", "Description": "Checks that there is at least one Kubernetes audit log configuration defined with security best practices. This rule is COMPLIANT if there is at least one configuration that meets all of the following criteria: audit logs are enabled, retention policies are set, and sensitive request logging is implemented.", - "Name": "Kubernetes Audit Logs", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Audit Logs" + "Service": "API Server" } ] }, { "Id": "10.3.3.5", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) are using encrypted storage classes with specific encryption keys. The rule is NON_COMPLIANT if a PVC is not using an encrypted storage class or is using an encryption key not specified in the rule parameter.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.6", "Description": "Checks if Kubernetes Secrets are created with encryption at rest enabled. The rule is COMPLIANT if the 'encryption' key is defined in the Kubernetes configuration.", - "Name": "Kubernetes Secrets", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Secrets" + "Service": "API Server" } ] }, { "Id": "10.3.3.7", "Description": "Checks if Kubernetes Audit Logging is configured to generate logs with proper validation. Kubernetes recommends that log validation must be enabled for auditing to ensure integrity and reliability of the logs. The rule is NON_COMPLIANT if audit logging validation is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.3.8", - "Description": "Checks if RDS DB instances have backups enabled. Optionally, the rule checks the backup retention period and the backup window.", - "Name": "AWS RDS", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "AWS RDS" + "Service": "API Server" } ] }, { "Id": "10.3.3.9", "Description": "Checks whether a Kubernetes Persistent Volume (PV) is included in a Backup Storage Class. The rule is NON_COMPLIANT if Persistent Volumes are not present in any Backup Storage Class.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -8157,78 +7719,78 @@ { "Id": "10.3.3.11", "Description": "Checks if Kubernetes Persistent Volumes are protected by a backup plan. The rule is NON_COMPLIANT if the Persistent Volume is not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.12", "Description": "Check if Kubernetes Persistent Volumes (PVs) are included in backup plans. The rule is NON_COMPLIANT if Persistent Volumes are not included in backup plans.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.3.13", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are protected by a backup plan. The rule is NON_COMPLIANT if the Persistent Volume is not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.14", "Description": "Checks if Kubernetes Pods are protected by a backup plan. The rule is NON_COMPLIANT if the Kubernetes Pod is not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.3.15", "Description": "Checks if Persistent Volume Claims (PVCs) that are backed by Persistent Volumes (PVs) are included in backup plans for Kubernetes clusters. The rule is NON_COMPLIANT if PVCs backed by PVs are not included in the backup plans.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.16", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are protected by a backup policy. The rule is NON_COMPLIANT if the PV is not covered by a backup policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -8247,302 +7809,266 @@ { "Id": "10.3.3.18", "Description": "Checks if Kubernetes Persistent Volumes are protected by a backup plan. The rule is NON_COMPLIANT if the Persistent Volume is not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.3.19", - "Description": "Checks if a Kubernetes StatefulSet's persistent volume claims have a retention period set to a specific duration. The rule is NON_COMPLIANT if the retention period is less than the value specified by the parameter.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.3.3.20", - "Description": "Checks if Kubernetes databases managed by StatefulSets or Deployments are included in backup plans. The rule is NON_COMPLIANT if any database is not included in a backup plan.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.21", "Description": "Checks if Kubernetes persistent volumes are protected by a backup plan. The rule is NON_COMPLIANT if the persistent volume is not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.3.22", "Description": "Checks that Kubernetes persistent volume claims (PVCs) are configured with appropriate storage requests that are not less than the minimum required size and not greater than the maximum allowed size. The rule is NON_COMPLIANT if the size of the PVC is less than MinStorageSize or greater than MaxStorageSize.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.3.23", "Description": "Checks if Kubernetes Services are publicly accessible. The rule is NON_COMPLIANT if a Service is not listed in the excludedPublicServices parameter and its type is LoadBalancer or NodePort.", - "Name": "Kubernetes Services", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Services" + "Service": "API Server" } ] }, { "Id": "10.3.3.24", "Description": "Checks if Kubernetes persistent volume claims (PVCs) are protected by a backup solution. The rule is NON_COMPLIANT if the persistent volume claims are not covered by a backup plan.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.3: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.4.1", "Description": "Checks if a Kubernetes Ingress resource backed by a Service of type 'ClusterIP' has appropriate annotations for secure TLS configuration. The rule is NON_COMPLIANT if the Ingress resource is configured to route traffic to a 'ClusterIP' Service and does not have the required TLS annotations, or the Service is not of type 'ClusterIP'.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.4.2", "Description": "Checks if a Kubernetes Ingress resource has annotation for access control enabled. The rule is NON_COMPLIANT for Ingress resources that don't have access control enabled for services.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.3.4.3", "Description": "Checks that there is at least one Kubernetes Auditing configuration defined with security best practices. This rule is COMPLIANT if there is at least one audit policy that meets all of the following criteria: properly configured for logging, retains logs for an appropriate timeframe, and includes all critical API requests.", - "Name": "Kubernetes Audit", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Audit" + "Service": "API Server" } ] }, { "Id": "10.3.4.4", "Description": "Verifies if Kubernetes Secrets are encrypted with a specified KMS provider or a custom key. The check is NON_COMPLIANT if a Secret is not encrypted with any KMS provider or is encrypted with a key not defined in the policy.", - "Name": "Kubernetes Secrets", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Secrets" + "Service": "Core" } ] }, { "Id": "10.3.4.5", "Description": "Checks if Kubernetes secrets are configured to use encryption at rest. The rule is COMPLIANT if the encryption configuration specifies a valid encryption provider with secrets encryption enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.4.6", "Description": "Checks if Kubernetes Audit Logs are configured to include a signature for log integrity. It is recommended that the audit log validation feature must be enabled across all namespaces. The rule is NON_COMPLIANT if the validation is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.3.4.7", "Description": "Checks if the Kubernetes PersistentVolume has a retention policy enabled. The rule is NON_COMPLIANT if the retention policy is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.3.4.8", "Description": "Checks if Kubernetes persistent volumes (PVs) are improperly exposed. The rule is NON_COMPLIANT if a PV is not listed in the excludedPersistentVolumes parameter and its access mode allows public access.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.3.4.9", "Description": "Checks if versioning is enabled for your Kubernetes Persistent Volume Claims (PVCs). Optionally, the rule checks if data protection features like volume snapshots are enabled for your PVCs.", - "Name": "Kubernetes Persistent Volumes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "10.3.4: Audit logs are protected from destruction and unauthorized modifications.", - "Service": "Kubernetes Persistent Volumes" + "Service": "RBAC" } ] }, { "Id": "10.4.1.1.1", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress controllers. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes Ingress" - } - ] - }, - { - "Id": "10.4.1.1.2", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert for the named metric. For resource type, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource ID and Prometheus alert.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.1.1.3", "Description": "Checks if Kubernetes Audit Logs are configured to be sent to a logging service. The audit policy is considered NON_COMPLIANT if the output configuration for audit logs does not include a specified logging endpoint.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.1.1.4", "Description": "Checks if detailed monitoring is enabled for Kubernetes Pods. The rule is NON_COMPLIANT if detailed monitoring is not enabled, indicating that metrics for resource usage and performance are not being collected aggressively.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.1.1.5", "Description": "Checks if the Kubernetes Pod Security Policies are enabled for a Kubernetes cluster. The rule is NON_COMPLIANT if Pod Security Policies are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.1.1.6", "Description": "Checks if Kubernetes Event Exporter is configured to log delivery status of events sent to a specific namespace or resource. The rule is NON_COMPLIANT if the delivery status logging for events is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.1.1.7", "Description": "Checks if metrics collection for Kubernetes Ingress resources is enabled. The rule is NON_COMPLIANT if the 'metrics.enabled' field is set to false in the Ingress controller configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.4.1.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, @@ -8558,79 +8084,67 @@ } ] }, - { - "Id": "10.4.1.2", - "Description": "Checks if a Kubernetes resource type has an associated Prometheus alert for the named metric. For resource type, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource name and Prometheus alert.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.4.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" - } - ] - }, { "Id": "10.4.1.3", "Description": "Checks if detailed monitoring is enabled for Kubernetes Pods. The rule is NON_COMPLIANT if detailed monitoring is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.1.4", "Description": "Checks if a Kubernetes cluster has the PodSecurityPolicy enabled. The rule is NON_COMPLIANT if PodSecurityPolicies are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.4.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.1.5", "Description": "Checks if Kubernetes events logging is enabled for the delivery status of notification messages sent to endpoints. The rule is NON_COMPLIANT if the delivery status notification for messages is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.1.6", "Description": "Checks if Kubernetes auditing is enabled on the cluster. The status is NON_COMPLIANT if the 'audit.log' is not configured or the logging level is set to off.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.4.1: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.2.1", "Description": "Checks if OpenTelemetry tracing is enabled for Kubernetes Ingress controllers. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, @@ -8646,77 +8160,65 @@ } ] }, - { - "Id": "10.4.2.3", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert configured for the specified metric. For resource types, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource name and Prometheus alert.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" - } - ] - }, { "Id": "10.4.2.4", "Description": "Checks if the Kubernetes cluster has the appropriate monitoring set up using tools like Prometheus or Grafana. The rule is NON_COMPLIANT if monitoring is not enabled for the pods or nodes.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.2.5", "Description": "Checks if Kubernetes Pod Security Policies are enabled in a cluster. The rule is NON_COMPLIANT if Pod Security Policies are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.4.2.6", "Description": "Checks if Kubernetes Event logging is enabled for the delivery status of notification messages sent to a service. The rule is NON_COMPLIANT if the delivery status notification for messages is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.2.7", "Description": "Checks if Kubernetes resource monitoring metrics collection is enabled for a specific deployment or pod. The resource is considered NON_COMPLIANT if the 'spec.monitoring.enabled' field is set to false.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.2: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.4.3.1", "Description": "Checks if Kubernetes alerts (such as those from Prometheus Alertmanager) have an action configured for firing, pending, or resolved states. Optionally checks if any actions match a specific handler or notification channel. The rule is NON_COMPLIANT if there is no action specified for the alert or the optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.4.3: Audit logs are reviewed to identify anomalies or suspicious activity.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -8747,746 +8249,698 @@ { "Id": "10.5.1.3", "Description": "Checks that there is at least one Kubernetes Audit Policy defined with security best practices. This rule is COMPLIANT if there is at least one Audit Policy that meets all of the following security standards.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.5.1.4", "Description": "Checks if a Kubernetes Log retention policy is set to retain logs for more than 365 days or a specified retention period. The rule is NON_COMPLIANT if the retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_maxage_set" ], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.5.1.5", "Description": "Checks if a Kubernetes Persistent Volume Claim (PVC) retention period is set to a specific number of days. The rule is NON_COMPLIANT if the retention period is less than the value specified by the parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.6", "Description": "Checks if point-in-time recovery (PITR) is enabled for Kubernetes persistent volume claims (PVCs). The rule is NON_COMPLIANT if PITR is not enabled for PVCs.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.7", "Description": "Checks if Persistent Volumes (PVs) are bound to Persistent Volume Claims (PVCs), and optionally checks if the PVCs have a 'reclaimPolicy' set to 'Delete' when the associated Pods are terminated.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.8", "Description": "Checks if a private Kubernetes Container Registry (e.g., Google Container Registry, Docker Registry) has at least one lifecycle policy configured. The rule is NON_COMPLIANT if no lifecycle policy is configured for the private registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.9", "Description": "Checks if Kubernetes clusters are configured to send logs to a centralized logging service (e.g., Fluentd, ELK stack). The rule is COMPLIANT if logging is enabled for the pods in the cluster. This rule is NON_COMPLIANT if logging is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.10", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.5.1.11", "Description": "Checks if Kubernetes clusters are configured to send logs to a logging solution (like Elasticsearch or a centralized logging system). The rule is NON_COMPLIANT if logging is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.12", "Description": "Checks if a Kubernetes PersistentVolume (PV) has a reclaim policy set to 'Delete' or 'Retain'. The PersistentVolume is CONFLICTING if there are no reclaim policy settings or the policy does not match the specified criteria.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.5.1.13", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) have lifecycle policies configured to automatically manage the lifecycle of storage resources. The rule is NON_COMPLIANT if the lifecycle policy is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.5.1: Audit log history is retained and available for analysis.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' is not present in the Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.6.3.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if access logging is not enabled, or if the logging level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.6.3.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress resources. The rule is COMPLIANT if tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.6.3.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or if 'logLevel' is neither ERROR nor ALL.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "10.6.3.5", "Description": "Checks if Kubernetes Services are configured with an appropriate session affinity mode. The rule is NON_COMPLIANT if the service's session affinity does not match the user-defined session affinity settings.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "10.6.3.6", "Description": "Checks if Kubernetes Ingress resources are configured to log HTTP traffic to a specified logging service. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "10.6.3.7", "Description": "Checks if at least one Kubernetes Audit Policy is configured to log events for all API calls related to Pods. The rule is NON_COMPLIANT if there are no audit policies or if no policies record Pod events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.8", "Description": "Checks if Kubernetes events have a corresponding alert configured in Prometheus for critical states. Optionally checks if any alerts match a specific label selector. The rule is NON_COMPLIANT if there is no alert specified for the event or optional parameter.", - "Name": "Prometheus", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Prometheus" - } - ] - }, - { - "Id": "10.6.3.9", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert for the named metric. For resource type, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource ID and Prometheus alert.", - "Name": "Prometheus", - "Checks": [], - "Attributes": [ - { - "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Prometheus" - } - ] - }, - { - "Id": "10.6.3.10", - "Description": "The rule identifier for enabling CloudTrail is CLOUD_TRAIL_ENABLED, while the rule name used in the implementation is cloudtrail-enabled.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "AWS CloudTrail" + "Service": "Core" } ] }, { "Id": "10.6.3.11", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism (e.g., Fluentd, Logstash) enabled. The rule is NON_COMPLIANT if all logging configurations are set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.12", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes Pod events. The rule is NON_COMPLIANT if logging is not enabled or Pod logging has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.13", "Description": "Checks if a Kubernetes cluster has audit logging enabled for its API server. The rule is NON_COMPLIANT if audit logging is not enabled for the API server in the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.14", "Description": "Checks if Kubernetes has logging enabled for its client connections to ensure compliance. The rule is NON_COMPLIANT if the 'logging.enabled' setting is set to false in the Kubernetes API Server configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.15", "Description": "Checks if detailed monitoring is enabled for Pods in Kubernetes. The rule is NON_COMPLIANT if detailed monitoring (e.g., custom metrics or logging) is not set up for the Pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.16", "Description": "Checks if Kubernetes Pods have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the Pod security context is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.17", "Description": "Checks if logging is configured for active Kubernetes Pods. This rule is NON_COMPLIANT if an active Pod does not have the logging configuration (such as a sidecar for logging or specific logging annotations) defined or the value for logging is null in at least one container in the Pod specification.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "10.6.3.18", "Description": "Checks if a Kubernetes cluster has logging enabled via a logging solution like Fluentd or Elasticsearch. The rule is NON_COMPLIANT if logging is not enabled for all log types (e.g., application logs, system logs, audit logs).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.19", "Description": "Checks if Kubernetes clusters are configured to send logs to a centralized logging solution (like Elasticsearch or fluentd). The rule is NON_COMPLIANT if the value of 'logOptions' is not configured properly or set to false.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.20", "Description": "Checks if the Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if the ingress annotations for 'nginx.ingress.kubernetes.io/access-log' are not set to true or the 'nginx.ingress.kubernetes.io/access-log-bucket' annotation does not match the specified S3 bucket name.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "10.6.3.21", "Description": "Verifies if Kubernetes users (or service accounts) are associated with at least one Role or ClusterRole binding.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "Role-Based Access Control (RBAC)", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "Role-Based Access Control (RBAC)" } ] }, { "Id": "10.6.3.22", "Description": "Checks if Kubernetes clusters have auditing enabled. The rule is NON_COMPLIANT if auditing is not enabled for a cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.23", "Description": "Checks if a Kubernetes cluster has auditing enabled and configured properly. The rule is NON_COMPLIANT if auditing is not enabled or configured as required.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.6.3.24", - "Description": "In Kubernetes, the equivalent concept to monitoring multi-region cloud resources could be represented via a combination of multi-cluster or multi-namespace configurations along with monitoring tools like Prometheus or Grafana, ensuring observability across different geographical locations, similar to how a cloud trail would log events across multiple regions.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.25", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if an audit log is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.26", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.6.3.27", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not configured for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.28", "Description": "Checks if Kubernetes pods have logging enabled to send logs to a centralized logging system, such as Elasticsearch or Fluentd. The rule is NON_COMPLIANT if pods do not have proper logging configurations to push logs to the centralized logging system.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.29", "Description": "Checks if respective logs of Kubernetes clusters are enabled. The rule is NON_COMPLIANT if any log types such as audit logs or application logs are not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.30", "Description": "Checks if Kubernetes clusters are configured to log audits to a specific log destination. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.31", "Description": "Checks if Kubernetes clusters have the specified security settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not using encryption for secrets, or if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "10.6.3.32", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "10.6.3.33", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted verbs (e.g., 'get', 'delete') on resources within a namespace for principals from other namespaces. For example, the rule checks that the Role or ClusterRole does not allow any actions like 'get pods' or 'delete deployments' on resources within any namespace. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.34", "Description": "Checks if logging is enabled for your Kubernetes pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.35", "Description": "Verifies that the Kubernetes ClusterRole and RoleBinding do not grant permissions to access resources across different namespaces unless explicitly specified by the control policies you define.", - "Name": "Kubernetes RBAC (Role-Based Access Control)", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes RBAC (Role-Based Access Control)" + "Service": "RBAC" } ] }, { "Id": "10.6.3.36", "Description": "Checks if a specific Kubernetes cluster has the PodSecurity admission controller enabled. The rule is NON_COMPLIANT if the PodSecurity admission controller is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.6.3.37", "Description": "Checks if Kubernetes Event Logging is enabled for the delivery status of event notifications sent to a namespace. The rule is NON_COMPLIANT if the event logging for notifications is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.38", "Description": "Checks if Kubernetes Pod has logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging configured or the logging level is below the minimum required settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.39", "Description": "Checks if Kubernetes Network Policies are applied and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not configured for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.6.3.40", "Description": "Checks if logging is enabled on Kubernetes Network Policies. The rule is NON_COMPLIANT if logging is enabled but the logging destination does not match the specified value.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "10.6.3.41", "Description": "Checks if Kubernetes Network Policy metrics collection on a specific Network Policy is enabled. The policy is NON_COMPLIANT if the 'spec.policyTypes' field does not include 'Ingress' or 'Egress'.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.6.3.42", "Description": "Checks if logging is enabled on Kubernetes Network Policies. The rule is NON_COMPLIANT for a Network Policy if it does not have logging enabled.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.6.3: Time-synchronization mechanisms support consistent time settings across all systems.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "10.7.1.1", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes REST APIs. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes API", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes API" + "Service": "API Server" } ] }, { "Id": "10.7.1.2", "Description": "Checks if your Kubernetes deployments send event notifications to a designated service, such as an external monitoring tool or messaging system (e.g., Slack, PagerDuty). Optionally checks if specified external services are used. The rule is NON_COMPLIANT if Kubernetes deployments do not send notifications.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.1.3", "Description": "Checks if Kubernetes PodDisruptionBudgets have a specified action for the conditions when 'disruptionAllowed' is not adhered to, i.e., when disruptions are allowed or not allowed. Optionally checks if any actions match a specific label or annotation. The rule is NON_COMPLIANT if there is no action specified for the PodDisruptionBudget or the optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.7.1.4", - "Description": "Checks if a Kubernetes resource type (such as Pods, Deployments, or StatefulSets) has a Prometheus alert for the specified metric. The rule is COMPLIANT if the named metric has a resource identifier and a corresponding Prometheus alert.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.1.5", "Description": "Checks if detailed monitoring is enabled for Kubernetes Pods. The rule is NON_COMPLIANT if detailed monitoring (such as Prometheus metrics) is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.1.6", "Description": "Checks if Kubernetes Pod Security Policy is enabled for a Kubernetes cluster. The rule is NON_COMPLIANT if Pod Security Policy is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -9505,336 +8959,288 @@ { "Id": "10.7.1.8", "Description": "Checks if Kubernetes logging for security metrics collection on a specific Pod or Deployment is enabled. The rule is NON_COMPLIANT if the 'logging.enabled' field is set to false.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.1: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.2.1", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes services. The rule is COMPLIANT if tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes Services" - } - ] - }, - { - "Id": "10.7.2.2", - "Description": "Checks if your Kubernetes resources (such as Deployments or StatefulSets) send event notifications to an external notification system (like an SNS topic). Optionally checks if specified notification endpoints are used. The rule is NON_COMPLIANT if Kubernetes resources do not send notifications.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.2.3", "Description": "Checks if Kubernetes custom resource alerts (e.g., Prometheus Alertmanager alerts) have an action configured for firing (ALARM), pending (INSUFFICIENT_DATA), or resolved (OK) states. Optionally checks if any actions match a specified Kubernetes resource (like a Service or Deployment). The rule is NON_COMPLIANT if there is no action specified for the alert or optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "10.7.2.4", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert for the named metric. For resource types, you can specify Pods, Deployments, StatefulSets, or Services. The rule is COMPLIANT if the named metric has a resource ID and Prometheus alert.", - "Name": "Prometheus", - "Checks": [], - "Attributes": [ - { - "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Prometheus" + "Service": "Core" } ] }, { "Id": "10.7.2.5", "Description": "Checks if Prometheus monitoring is enabled for Kubernetes pods. The rule is NON_COMPLIANT if Prometheus monitoring is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.2.6", "Description": "Checks if the Kubernetes Security Context is configured for a Pod. The rule is NON_COMPLIANT if the Security Context is not defined, which could lead to security vulnerabilities.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "10.7.2.7", "Description": "Checks if Kubernetes Event Logging is enabled for the delivery status of events sent to a namespace or pod. The rule is NON_COMPLIANT if the event logging for messages is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "10.7.2.8", "Description": "Checks if the Kubernetes security metrics collection is enabled for Network Policies. The rule is NON_COMPLIANT if the 'spec.metrics.enabled' field is set to false.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "10.7.2: Failures of critical security control systems are detected, reported, and responded to promptly.", - "Service": "Kubernetes Network Policies" - } - ] - }, - { - "Id": "11.3.1.1.1", - "Description": "Verifies that all specified Kubernetes applications (such as Deployments, StatefulSets, etc.) are deployed and running in the cluster. Optionally, it can check for the minimum acceptable version of these applications. Additionally, it can be scoped to certain nodes based on their labels or annotations to apply the check only to nodes matching a specified platform.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "11.3.1.1: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "11.3.1.1.2", "Description": "Checks if the compliance status of the Kubernetes node's patch compliance is UP_TO_DATE or OUTDATED after the patch installation on the node. The rule is compliant if the field status is UP_TO_DATE.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1.1: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.3.1.2.1", "Description": "Checks if a private Kubernetes container registry has image scanning enabled. The rule is NON_COMPLIANT if the container images in the registry are not scanned regularly for vulnerabilities or are not scanned upon image push. For detailed information on enabling image scanning, refer to the Kubernetes container security best practices documentation.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1.2: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.3.1.3.1", "Description": "Verifies that all specified Kubernetes applications (pods or deployments) are present in the cluster, with the option to check for minimum acceptable versions and to target specific node/platform types.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1.3: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.3.1.3.2", "Description": "Checks if the compliance status of a Kubernetes pod's deployment is READY or NOT_READY after updates or changes to the pod. The rule is compliant if the condition status is READY.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1.3: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.3.1.3.3", "Description": "Checks if a private Kubernetes container registry has image scanning enabled. The rule is NON_COMPLIANT if the private container registry's scan policy is not set to scan on push or continuous scan.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1.3: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "11.3.1.1", - "Description": "Verifies if all specified Kubernetes applications (such as Deployments, StatefulSets, etc.) are deployed in the cluster. Optionally, the minimum required version of each application can be checked. Additionally, the rule can be limited to specific node selectors or taints to target nodes running on certain platforms.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "11.3.1: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.3.1.2", "Description": "Checks if the compliance status of the Kubernetes deployment is 'COMPLIANT' or 'NON_COMPLIANT' after the update to the application. The rule is compliant if the status field in the deployment returns 'COMPLIANT'.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "11.3.1.3", "Description": "Checks if a private Kubernetes container registry (e.g., Azure Container Registry, Google Container Registry) has image scanning enabled. The rule is NON_COMPLIANT if the container registry's scan frequency is not set to scan on push or continuous scan.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.3.1: External and internal vulnerabilities are regularly identified, prioritized, and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.5.1.1.1", "Description": "Checks whether a Kubernetes LoadBalancer Service or Ingress resource has any associated protection mechanisms, such as network policies for security, and if they have specified Ingress rules associated for additional security configurations.", - "Name": "Kubernetes LoadBalancer Service / Ingress", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "11.5.1.1: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes LoadBalancer Service / Ingress" + "Service": "Core" } ] }, { "Id": "11.5.1.1.2", "Description": "Checks if Kubernetes Pod Security Policies are enabled in your Kubernetes cluster. If you provide a central management cluster, the policy evaluates the Pod Security results in the centralized context. The policy is COMPLIANT when Pod Security Policies are enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "11.5.1.1: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "11.5.1.1", "Description": "Checks whether a Kubernetes Service has Network Policies or Ingress controllers configured for protection against DDoS attacks. It also checks if they have specific authorization rules defined for the Ingress resources.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "11.5.1: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "11.5.1.2", "Description": "Checks if Kubernetes Pod Security Policies are enabled in your Kubernetes cluster. If you provide a cluster for centralization, the rule evaluates the Pod Security Policies in the centralized cluster. The rule is COMPLIANT when Pod Security Policies are enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "11.5.1: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "11.5.2.1", "Description": "Checks if your Kubernetes resources (like Pods, Deployments, etc.) send event notifications to a designated Pub/Sub topic. Optionally checks if specified Pub/Sub topics are utilized. The rule is NON_COMPLIANT if Kubernetes resources do not send notifications.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.5.2: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.5.2.2", "Description": "Verifies if Kubernetes liveness probes or readiness probes have valid actions configured for different states. It checks if any actions are set to change the pod's status based on these probes. The rule is NON_COMPLIANT if no actions are specified for the probes.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.5.2: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "11.5.2.3", "Description": "Verifies if Kubernetes alerts configured in Prometheus with the specified metric name meet the defined conditions.", - "Name": "Prometheus", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.5.2: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Prometheus" + "Service": "Core" } ] }, { "Id": "11.5.2.4", "Description": "Checks if Kubernetes audit logs are configured to send logs to a log management system like Elasticsearch or a logging solution such as Fluentd or another log aggregator. The audit logging is NON_COMPLIANT if the output destination is not specified or if the audit log file is not configured.", - "Name": "Kubernetes Audit Logging", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "11.5.2: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "11.5.2.5", "Description": "Checks if Kubernetes Event Notifications for a specific resource (e.g., Pod or Service) are enabled. The rule is NON_COMPLIANT if Event Notifications are not set on the resource, or if the event type or notification endpoint do not match the expected event types and notification URL.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.5.2: Network intrusions and unexpected file changes are detected and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -9850,27 +9256,15 @@ } ] }, - { - "Id": "11.6.1.1", - "Description": "Checks if your Kubernetes resources (such as Deployments or StatefulSets) send event notifications to a specified messaging service (such as NATS or RabbitMQ). Optionally checks if specific messaging queues or topics are utilized for notifications. The rule is NON_COMPLIANT if Kubernetes resources do not send notifications.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "11.6.1: Unauthorized changes on payment pages are detected and responded to.", - "Service": "Kubernetes" - } - ] - }, { "Id": "11.6.1.2", "Description": "Checks if Kubernetes Horizontal Pod Autoscaler (HPA) has correctly configured scaling actions for different metrics. Optionally checks if any scaling actions match a specific deployment or resource. The rule is NON_COMPLIANT if there are no scaling actions defined for the HPA or optional parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.6.1: Unauthorized changes on payment pages are detected and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -9889,14 +9283,14 @@ { "Id": "11.6.1.4", "Description": "Checks if Kubernetes Audit Logs are configured to send logs to a specified logging service. The audit logging is NON_COMPLIANT if the logging configuration does not point to an active logging backend such as Elasticsearch or a central logging service.", - "Name": "Kubernetes Audit Logging", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "11.6.1: Unauthorized changes on payment pages are detected and responded to.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, @@ -9915,36 +9309,24 @@ { "Id": "11.6.1.6", "Description": "Checks if Kubernetes Event Logging is enabled for the delivery status of events sent to a specified namespace. The rule is NON_COMPLIANT if the event logging for notifications is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "11.6.1: Unauthorized changes on payment pages are detected and responded to.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "12.10.5.1", - "Description": "Checks if your Kubernetes resources (like Deployments or StatefulSets) are configured to send events to an external notification system, such as an SNS-like service. Optionally checks if specified notification endpoints are used. The rule is NON_COMPLIANT if Kubernetes resources do not send notifications.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "12.10.5: Suspected and confirmed security incidents that could impact the CDE are responded to immediately.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "12.10.5.2", "Description": "Checks if Kubernetes PodDisruptionBudgets (PDBs) have a set number of allowed disruptions configured. Optionally checks if any disruptions match a specific label selector. The rule is NON_COMPLIANT if there are no disruptions allowed in the PDB or optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "12.10.5: Suspected and confirmed security incidents that could impact the CDE are responded to immediately.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -9963,26 +9345,26 @@ { "Id": "12.10.5.4", "Description": "Checks if Kubernetes audit logging is configured to send logs to a specified logging backend. The audit policy is NON_COMPLIANT if the audit backend configuration is not set or if the logging destination is empty.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "12.10.5: Suspected and confirmed security incidents that could impact the CDE are responded to immediately.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "12.10.5.5", "Description": "Checks if Kubernetes events are enabled for a specific resource. The rule is NON_COMPLIANT if events are not set for the resource, or if the event type or destination do not match the eventTypes and destination parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "12.10.5: Suspected and confirmed security incidents that could impact the CDE are responded to immediately.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10001,154 +9383,154 @@ { "Id": "12.4.2.1.1", "Description": "Checks if a Kubernetes cluster shares resources (like ConfigMaps or Secrets) to multiple namespaces when integration is enabled with Kubernetes RBAC. The rule is NON_COMPLIANT if the resource is scoped to a single namespace instead of being cluster-wide.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "12.4.2.1: PCI DSS compliance is managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "2.2.5.1", "Description": "Checks if HTTP to HTTPS redirection is configured on all Ingress resources of the Kubernetes cluster. The rule is NON_COMPLIANT if one or more Ingress resources do not have an HTTP to HTTPS redirection configured. The rule is also NON_COMPLIANT if one or more Ingress resources have forwarding to an HTTP service instead of redirection.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.2", "Description": "Checks if Kubernetes Ingress resources are using deprecated SSL protocols for HTTPS communication between Ingress controllers and backend services. This rule is NON_COMPLIANT if any Ingress definition includes 'sslPolicy' that allows 'SSLv3'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.3", "Description": "Checks if Kubernetes Ingress resources are using a minimum security policy and cipher suite of TLSv1.2 or greater for HTTPS connections. This rule is NON_COMPLIANT for an Ingress resource if the minTLSVersion is below 'VersionTLS12'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.4", "Description": "Checks if Kubernetes Ingress resources are using a custom TLS secret and are configured to use SNI to serve HTTPS requests. The rule is NON_COMPLIANT if a custom TLS secret is associated but the Ingress is not configured for SNI.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.5", "Description": "Checks if Kubernetes Ingress resources are encrypting traffic to backend services. The rule is NON_COMPLIANT if 'backendService' is using unencrypted HTTP endpoints instead of HTTPS or if 'TLS settings' are not properly configured for secure connections.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.6", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS. The rule is NON_COMPLIANT if any Ingress resource allows HTTP traffic without redirecting to HTTPS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.7", "Description": "Check if Kubernetes pods that require encrypted communications between instances have TLS (Transport Layer Security) enabled for pod-to-pod communication. The rule is NON_COMPLIANT if TLS encryption is not enabled for these communications.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "2.2.5.8", "Description": "Checks whether your Kubernetes Ingress resources are using a custom SSL certificate for secure connections. This rule only applies if there are Ingress resources defined with SSL settings.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.9", "Description": "Checks if your Kubernetes Ingress resource uses a predefined TLS configuration. The rule is NON_COMPLIANT if the Ingress TLS configuration does not equal the value of the parameter 'predefinedPolicyName'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.10", "Description": "Checks if your Kubernetes Service is configured with TLS for secure communication. The rule is NON_COMPLIANT if a Service does not have an associated TLS configuration for HTTPS traffic.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "2.2.5.11", "Description": "Checks if Kubernetes clusters have Pod Security Policies enabled. The rule is NON_COMPLIANT if a Pod Security Policy is not attached to the cluster or the policy does not satisfy the specified rule parameters.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -10167,78 +9549,78 @@ { "Id": "2.2.5.13", "Description": "Check if Kubernetes Secrets are encrypted at rest and if communication between pods is encrypted. The rule is NON_COMPLIANT if encryption for Secrets is not enabled or if Network Policies do not ensure encrypted communication between pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "2.2.5.14", "Description": "Checks if Kubernetes clusters require TLS encryption for communication. The rule is NON_COMPLIANT if any Kubernetes cluster has the API Server's --insecure-port parameter set to a value other than 0, allowing unencrypted traffic.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "2.2.5.15", "Description": "Checks if Ingress resources have rules that require TLS for connections. The rule is NON_COMPLIANT if any Ingress resource allows HTTP connections without TLS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.5.16", "Description": "Checks if a Kubernetes service uses FTP for endpoint connection. The rule is NON_COMPLIANT if the service type is set to 'ClusterIP' with a port configuration for FTP (port 21).", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "2.2.5.17", "Description": "Verifies that NetworkPolicies in Kubernetes are configured to limit incoming traffic only to specified ports, ensuring that unrestricted traffic ('0.0.0.0/0' or '::/0') is not allowed except on authorized TCP or UDP ports. If there are NetworkPolicies that do not specify the allowed ports, they are considered NON_COMPLIANT.", - "Name": "NetworkPolicies", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "2.2.5: System components are configured and managed securely.", - "Service": "NetworkPolicies" + "Service": "Core" } ] }, { "Id": "2.2.7.1", "Description": "Checks if Ingress resources in Kubernetes are configured to redirect HTTP traffic to HTTPS. The rule is NON_COMPLIANT if one or more Ingress resources do not have HTTP to HTTPS redirection configured or if they forward traffic to another HTTP service instead of redirecting.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, @@ -10257,38 +9639,38 @@ { "Id": "2.2.7.3", "Description": "Checks if Kubernetes Ingress resources are enforcing SSL/TLS for traffic to backend services. The rule is NON_COMPLIANT if 'backendProtocol' is 'http' or if 'backendProtocol' is 'https' but 'tls' is not specified for the Ingress resource.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.7.4", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS connections. The rule is NON_COMPLIANT if the Ingress resource allows HTTP traffic without redirecting to HTTPS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.7.5", "Description": "Checks if your Kubernetes Pods have NetworkPolicies set to enforce traffic control. The rule is NON_COMPLIANT if a Pod is not restricted by NetworkPolicies to prevent unauthorized access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10307,28 +9689,28 @@ { "Id": "2.2.7.7", "Description": "Checks if Kubernetes clusters have TLS encryption enabled for communication between pods and services. The rule is NON_COMPLIANT if TLS encryption is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "2.2.7.8", "Description": "Checks if Kubernetes Secrets are encrypted in transit. The rule is NON_COMPLIANT for a Kubernetes cluster if 'encryptionProviders' are not configured to enable encryption for Secrets during transit.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10347,78 +9729,78 @@ { "Id": "2.2.7.10", "Description": "Checks if the Ingress resources in Kubernetes use SSL certificates provided by a Certificate Manager (e.g., Cert-Manager or similar). To use this rule, an Ingress resource should be configured with TLS settings. This rule is only applicable to Ingress resources. This rule does not check services without Ingress, such as NodePorts or ClusterIPs.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.7.11", "Description": "Checks whether your Kubernetes Ingress resources are using a custom TLS configuration. The rule is only applicable if there are TLS-enabled Ingress resources defined.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.7.12", "Description": "Checks if your Kubernetes Ingress controllers use a predefined TLS policy. The rule is NON_COMPLIANT if the Ingress TLS configuration does not match the specified 'predefinedPolicyName'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "2.2.7.13", "Description": "Checks if the Kubernetes Service is configured with HTTPS or SSL settings for its corresponding LoadBalancer. The rule is NON_COMPLIANT if the Service is not configured with SSL or HTTPS.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "2.2.7.14", "Description": "Verifies if Kubernetes clusters have security contexts with Kerberos enabled. The rule is NON_COMPLIANT if a security context is not defined for the pod or the security context does not satisfy the specified rule parameters for Kerberos authentication.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "2.2.7.15", "Description": "Checks if a Kubernetes cluster enforces encrypted communication (TLS) for inter-pod communication. The rule is NON_COMPLIANT if plain text communication is allowed between pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10437,38 +9819,38 @@ { "Id": "2.2.7.17", "Description": "Check if Kubernetes cluster nodes have encrypted communication enabled. The rule is NON_COMPLIANT if the encryption between nodes is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "2.2.7.18", "Description": "Checks if Kubernetes clusters require TLS/SSL encryption for connections to SQL clients. The rule is NON_COMPLIANT if any Kubernetes cluster has the configuration for TLS/SSL not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "2.2.7.19", "Description": "Checks if Kubernetes services have Network Policies that require requests to use secure connections (TLS). The rule is NON_COMPLIANT if any service allows HTTP traffic without enforcing TLS.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "2.2.7: System components are configured and managed securely.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -10508,51 +9890,27 @@ } ] }, - { - "Id": "3.2.1.4", - "Description": "Checks if a Kubernetes StatefulSet has a retention policy set for the PVCs that is equal to or greater than a specified number of days. The rule is NON_COMPLIANT if the retention policy is less than the specified value.", - "Name": "Kubernetes StatefulSet", - "Checks": [], - "Attributes": [ - { - "Section": "3.2.1: Storage of account data is kept to a minimum.", - "Service": "Kubernetes StatefulSet" - } - ] - }, - { - "Id": "3.2.1.5", - "Description": "Checks if point-in-time recovery (PITR) is enabled for the main persistent storage service within Kubernetes, such as a StatefulSet with a database service. The rule is NON_COMPLIANT if PITR functionality is not configured for the storage used by StatefulSets.", - "Name": "StatefulSet / Persistent Volume", - "Checks": [], - "Attributes": [ - { - "Section": "3.2.1: Storage of account data is kept to a minimum.", - "Service": "StatefulSet / Persistent Volume" - } - ] - }, { "Id": "3.2.1.6", "Description": "Checks if Persistent Volumes (PVs) are bound to Persistent Volume Claims (PVCs) in Kubernetes. Optionally checks if the storage class of the PVC specifies reclaim policy as 'Delete' when the PVC is deleted.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.2.1: Storage of account data is kept to a minimum.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.2.1.7", "Description": "Checks if a private Kubernetes container registry has at least one lifecycle policy configured. The rule is NON_COMPLIANT if no lifecycle policy is configured for the Kubernetes container registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.2.1: Storage of account data is kept to a minimum.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10571,12 +9929,12 @@ { "Id": "3.2.1.9", "Description": "Checks if Kubernetes persistent volumes (PVs) have lifecycle policies configured. The rule is NON_COMPLIANT if a Kubernetes persistent volume does not have a defined reclaim policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.2.1: Storage of account data is kept to a minimum.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10607,12 +9965,12 @@ { "Id": "3.3.1.1.3", "Description": "Checks if a Kubernetes Namespace's resource quota for log retention is set to greater than 365 days or else a specified retention limit. The rule is NON_COMPLIANT if the log retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10628,63 +9986,51 @@ } ] }, - { - "Id": "3.3.1.1.5", - "Description": "Checks if point-in-time recovery (PITR) is enabled for Kubernetes StatefulSets. The rule is NON_COMPLIANT if PITR is not enabled for StatefulSets.", - "Name": "Kubernetes StatefulSets", - "Checks": [], - "Attributes": [ - { - "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes StatefulSets" - } - ] - }, { "Id": "3.3.1.1.6", "Description": "Checks if Persistent Volumes (PVs) are bound to Persistent Volume Claims (PVCs). Optionally checks if PVCs have a finalizer to ensure they are deleted when the associated Pods are terminated.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.1.1.7", "Description": "Checks if a private Kubernetes container registry has at least one lifecycle policy configured. The rule is NON_COMPLIANT if no lifecycle policy is configured for the private registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.1.1.8", "Description": "Checks if a Kubernetes Persistent Volume (PV) has a Retain policy set for its lifecycle. The PV is considered NON_COMPLIANT if there are no active reclaim policies or the policies do not match the desired parameter values.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.1.1.9", "Description": "Checks if Kubernetes buckets (such as those used with object storage solutions like MinIO or cloud providers) have a lifecycle management policy configured. The rule is NON_COMPLIANT if the lifecycle policy is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.1: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10700,29 +10046,17 @@ } ] }, - { - "Id": "3.3.1.3.2", - "Description": "Checks if a Kubernetes PersistentVolumeClaim (PVC) retains data for a period that meets the specified retention policy. The rule is NON_COMPLIANT if the PVC's retention strategy is less than the required retention period.", - "Name": "PersistentVolumeClaim", - "Checks": [], - "Attributes": [ - { - "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "PersistentVolumeClaim" - } - ] - }, { "Id": "3.3.1.3.3", "Description": "Checks if a Kubernetes Cluster's Log retention policy is set to retain logs for more than 365 days. The policy is NON_COMPLIANT if the retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_maxage_set" ], "Attributes": [ { "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -10753,50 +10087,38 @@ { "Id": "3.3.1.3.6", "Description": "Checks if Persistent Volumes (PVs) are bound to Persistent Volume Claims (PVCs). Optionally checks if the volumes are set to delete upon PVC deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.1.3.7", "Description": "Checks if a private Kubernetes container registry has at least one lifecycle policy configured. The rule is NON_COMPLIANT if no lifecycle policy is configured for the Kubernetes container registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.3.1.3.8", - "Description": "Checks if a Kubernetes PersistentVolumeClaim (PVC) has a defined storage class and lifecycle rules. The claim is NON_COMPLIANT if there are no active storage class settings or the settings do not match the specified parameters.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.1.3.9", "Description": "Checks if Kubernetes Persistent Volumes (PVs) have a retention policy configured. The rule is NON_COMPLIANT if a retention policy is not enabled on the Persistent Volume.", - "Name": "Kubernetes Persistent Volumes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.3.1.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes Persistent Volumes" + "Service": "RBAC" } ] }, @@ -10827,24 +10149,12 @@ { "Id": "3.3.2.3", "Description": "Checks if a Kubernetes Pod's logging retention policy is set to greater than 365 days or a specified minimum retention time. The rule is NON_COMPLIANT if the retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.3.2.4", - "Description": "Checks if a Kubernetes StatefulSet's `spec.revisionHistoryLimit` is set to a specific number of revisions (days can be interpreted as a number of revisions). The rule is NON_COMPLIANT if the revision history limit is less than the value specified by the parameter.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10863,48 +10173,48 @@ { "Id": "3.3.2.6", "Description": "Checks if Persistent Volumes (PVs) are bound to Pods in a Kubernetes cluster. Optionally checks if Persistent Volumes are configured to be deleted when their associated Pods are deleted.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.2.7", "Description": "Checks if a private Kubernetes image registry has at least one lifecycle policy configured. The rule is NON_COMPLIANT if no lifecycle policy is configured for the Kubernetes private image registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.2.8", "Description": "Checks if a Kubernetes Persistent Volume (PV) has a defined reclaim policy. The status is NON_COMPLIANT if there is no active reclaim policy or the policy does not match the required values.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.3.2.9", "Description": "Checks if Kubernetes persistent volumes have lifecycle policies configured. The rule is NON_COMPLIANT if Kubernetes persistent volumes do not have lifecycle policies enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.2: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10935,26 +10245,26 @@ { "Id": "3.3.3.3", "Description": "Checks if a Kubernetes Cluster's log retention policy for the logging service is set to retain logs for more than 365 days or else a specified retention period. The rule is NON_COMPLIANT if the retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes Logging Service", + "Name": "API Server", "Checks": [ "apiserver_audit_log_maxage_set" ], "Attributes": [ { "Section": "3.3.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes Logging Service" + "Service": "API Server" } ] }, { "Id": "3.3.3.4", "Description": "Checks if a Kubernetes Persistent Volume Claim (PVC) storage class retention period is set to a specific value. The rule is NON_COMPLIANT if the retention period is less than the value specified by the parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -10985,12 +10295,12 @@ { "Id": "3.3.3.7", "Description": "Checks if a private Kubernetes container registry has at least one retention policy configured. The rule is NON_COMPLIANT if no retention policy is configured for the Kubernetes private container registry.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -11009,570 +10319,534 @@ { "Id": "3.3.3.9", "Description": "Checks if Kubernetes persistent volume claims (PVCs) have a storage lifecycle management policy configured. The rule is NON_COMPLIANT if the lifecycle policy for PVCs is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.3.3: Sensitive authentication data (SAD) is not stored after authorization.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.1.1", "Description": "Checks if Kubernetes Secrets that contain TLS certificates are about to expire within the specified number of days. TLS certificates in Kubernetes can be renewed, but manually managed certificates may not be automatically updated. The rule is NON_COMPLIANT if your certificates are about to expire.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "3.5.1.1.2", "Description": "Checks if Kubernetes CertificateSigningRequests (CSRs) exist that are not in 'Approved' status. The rule is NON_COMPLIANT for CSRs that are not approved by the controller (i.e., in 'Pending' status).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_csr_approval_access" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.1.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS secret for SSL termination.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.5.1.1.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is a custom SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate (kubernetes.io/tls-cert).", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.5.1.1.5", "Description": "Checks if Kubernetes Services of type LoadBalancer have TLS configured correctly using certificates from a trusted Certificate Authority (CA). This rule is NON_COMPLIANT if at least 1 LoadBalancer service has at least 1 listener (Ingress) that is configured without a valid TLS certificate from a supported CA or is configured with a certificate that is not trusted.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "API Server" } ] }, { "Id": "3.5.1.1.6", "Description": "Checks if the Ingress resources in Kubernetes use TLS certificates provided by a certificate management solution (like Cert-Manager). To use this rule, an Ingress resource with a TLS section must be configured in the cluster. This rule is only applicable to Ingress resources. This rule does not check for services without Ingress or other types of Load Balancers.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "3.5.1.1.7", "Description": "Checks if the Kubernetes Role or ClusterRole definitions do not allow actions on Kubernetes secrets that are disallowed by policy. The rule is NON_COMPLIANT if any disallowed action is permitted on Kubernetes secrets by the managed Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.1.8", "Description": "Checks if the Role-Based Access Control (RBAC) settings in your Kubernetes cluster do not allow blocked actions on all cluster resources. The rule is NON_COMPLIANT if any blocked action is allowed on any resources in the cluster role bindings.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.5.1.1.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.1", "Description": "Checks if Kubernetes TLS Secrets in your cluster are nearing expiration. Kubernetes does not automatically renew TLS Secrets. The rule is NON_COMPLIANT if your TLS Secrets are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.2", "Description": "Checks if Kubernetes Certificate Authority (CA) has a root CA that is disabled. The rule is NON_COMPLIANT for root CAs with status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.5.1.3.3", "Description": "Checks if a Kubernetes Ingress resource uses TLS. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS certificate.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Ingress" - } - ] - }, - { - "Id": "3.5.1.3.4", - "Description": "Checks if a Kubernetes PersistentVolume (PV) has a ResourceQuota in place that restricts deletions of PersistentVolumeClaims (PVCs) associated with it. The rule is NON_COMPLIANT if the PersistentVolume does not have an associated ResourceQuota or has a ResourceQuota that does not suitably deny 'DELETE' actions on PVCs.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.5", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default certificate. The rule is NON_COMPLIANT if the Ingress resource uses the default TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.6", "Description": "Checks if Kubernetes Pods are exposed to the public. The rule is NON_COMPLIANT if the Service type is set to 'LoadBalancer' or 'NodePort' without appropriate network policies.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.7", "Description": "Checks if Kubernetes persistent volume claims (PVCs) are publicly accessible. The rule is NON_COMPLIANT if any Kubernetes PVCs are accessible from outside the cluster.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.8", "Description": "Checks if Kubernetes Persistent Volume Claims (PVC) are not configured to allow public access. The rule is NON_COMPLIANT if any PVC has an access mode that allows public or excessive permissions, potentially exposing sensitive data.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.9", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the pod's SecurityContext is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.10", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are configured to use a specific mount path other than the default root directory. The rule is NON_COMPLIANT if the specified mount path is '/' (default root directory of the volume).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.11", "Description": "Checks if Kubernetes Persistent Volume (PV) access modes enforce a user identity. The rule is NON_COMPLIANT if 'spec.accessModes' is not defined to restrict access, or if specific user identities are not matched with the corresponding Access Control List (ACL) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.12", "Description": "Checks if Kubernetes Ingress resources are configured to use TLS certificates from a valid certificate issuer, such as cert-manager, ensuring that all Ingress resources have appropriate TLS settings. This rule is NON_COMPLIANT if at least one Ingress resource has at least one path that is configured without TLS or with a certificate not managed by the specified issuer.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.13", "Description": "Checks if the Ingress resources in Kubernetes use TLS certificates provided by Kubernetes Secrets. To use this rule, ensure that your Ingress controller is configured with an SSL or HTTPS listener. This rule is only applicable to Ingress resources managing traffic for services in Kubernetes. This rule does not check other types of services like LoadBalancer or NodePort services.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.14", "Description": "Checks if a Kubernetes cluster has network policies in place to block public access settings. The rule is NON_COMPLIANT if NetworkPolicy is not applied to deny all ingress traffic, or if a NetworkPolicy allows traffic from external sources on ports other than Port 22.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.15", "Description": "Checks if the Kubernetes Role or ClusterRole policies do not allow blocked actions on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes resources by the managed Role or ClusterRole policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.16", "Description": "Checks if the role-based access control (RBAC) permissions attached to your Kubernetes Service Accounts, Roles, and RoleBindings do not allow unauthorized actions on all Kubernetes resources. The rule is NON_COMPLIANT if any unauthorized action is allowed on all Kubernetes resources in the access control policies.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.17", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if any Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.18", "Description": "Checks if the Kubernetes Deployment configuration allows public access to its services through LoadBalancer type services or NodePort. If the Deployment configuration allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "3.5.1.3.19", "Description": "Checks if a Kubernetes PersistentVolume (PV) is public. The rule is NON_COMPLIANT if any existing and new PersistentVolume is accessible from outside the cluster.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.20", "Description": "Checks if the Kubernetes Pods are not exposed to the public. The rule is NON_COMPLIANT if the Pod's service type is LoadBalancer or NodePort, allowing external access.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "3.5.1.3.21", "Description": "Checks if Kubernetes PersistentVolume (PV) claims are publicly accessible. The rule is NON_COMPLIANT if any existing and new PersistentVolume claims have public access configurations.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.22", "Description": "Checks if Kubernetes clusters have public access enabled. The rule is NON_COMPLIANT if the service is exposed to the internet without proper configuration.", - "Name": "Kubernetes Cluster", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Cluster" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.23", "Description": "Checks if Kubernetes services have network policies applied that restrict public access. The rule is NON_COMPLIANT if network policies are not in place for the services.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.24", "Description": "Checks if the required network policies for public access are configured at the namespace level. The rule is only NON_COMPLIANT when the network policies do not match the corresponding configurations for public ingress/egress settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.25", "Description": "Checks if the required Kubernetes Network Policies are configured at the namespace level. The rule is NON_COMPLIANT if the configuration item does not match one or more settings from parameters (or default).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.26", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and the service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.5.1.3.27", - "Description": "Checks if Object Versioning is enabled in a Kubernetes PersistentVolumeClaim; the rule is NON_COMPLIANT if versioning is not enabled.", - "Name": "Kubernetes PersistentVolumeClaim", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes PersistentVolumeClaim" + "Service": "API Server" } ] }, { "Id": "3.5.1.3.28", "Description": "Checks if your Kubernetes persistent volumes do not allow public access. The rule checks the Persistent Volume settings, the StorageClass policies, and the Role-Based Access Control (RBAC) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.29", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public write access. The rule verifies the Persistent Volume Claims (PVC), the StorageClass settings, and the access modes of the Persistent Volumes (PV).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.3.30", "Description": "Checks if direct internet access is disabled for a Kubernetes Pod. The rule is NON_COMPLIANT if the Pod is allowed to access the internet.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.3.31", "Description": "Checks if Kubernetes ConfigMaps owned by the namespace are publicly accessible. The rule is NON_COMPLIANT if ConfigMaps with the owner 'Self' are accessible to unauthorized users.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1.3: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.1", "Description": "Checks if all methods in Kubernetes Ingress resources have caching enabled and are using TLS. The rule is NON_COMPLIANT if any method in a Kubernetes Ingress resource is not configured to use caching or is not served over TLS.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Ingress" - } - ] - }, - { - "Id": "3.5.1.2", - "Description": "Checks if a Kubernetes StatefulSet has persistent volume claims (PVCs) with encryption at rest enabled. The rule is NON_COMPLIANT if the persistent volumes used by the StatefulSet do not have encryption at rest enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -11603,196 +10877,146 @@ { "Id": "3.5.1.5", "Description": "Checks if Kubernetes Secrets are configured to use encryption at rest. The rule is COMPLIANT if the encryption provider configuration is defined in the Kubernetes API server configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.6", "Description": "Checks if a Kubernetes Job has encryption enabled for all of its secrets. The rule is NON_COMPLIANT if 'encryptionEnabled' is set to 'false' for any secrets used in the Job's specifications.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.5.1.7", - "Description": "Checks if the Kubernetes project (namespace/pod) contains environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. The rule is NON_COMPLIANT when the environment variables contain plaintext credentials.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.8", "Description": "Checks if a Kubernetes Pod's logs configured with a persistent volume have encryption enabled for its logs. The rule is NON_COMPLIANT if 'encryptionEnabled' is set to 'false' in the volume configuration of a Pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.9", "Description": "Checks if Kubernetes etcd clusters are encrypted at rest. The rule is NON_COMPLIANT if an etcd cluster is not encrypted.", - "Name": "etcd", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "etcd" + "Service": "ETCD" } ] }, { "Id": "3.5.1.10", "Description": "Checks if storage encryption is enabled for your Kubernetes Persistent Volume Claims (PVCs). The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.5.1.11", - "Description": "Checks if a Kubernetes PersistentVolumeClaim (PVC) is using encryption. The rule is NON_COMPLIANT if the PVC is not using an encrypted PersistentVolume, or if the specified encryption key is not present in the annotations for the PVC.", - "Name": "Kubernetes", - "Checks": [ - "rbac_minimize_pv_creation_access" - ], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.12", "Description": "Checks if the Kubernetes etcd database is encrypted and checks its status. The rule is COMPLIANT if the status is enabled or enabling.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, { "Id": "3.5.1.13", "Description": "Checks if Kubernetes Persistent Volume (PV) encryption at rest is enabled by default. The rule is NON_COMPLIANT if the encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.14", "Description": "Checks if Kubernetes Secrets are exposed as environment variables in Pods. The rule is NON_COMPLIANT if one or more environment variable key matches a key listed in the 'secretKeys' parameter, excluding environment variables sourced from other locations such as ConfigMaps.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "3.5.1.15", "Description": "Checks if Kubernetes Persistent Volume (PV) is configured to encrypt the data using Kubernetes Secrets for key management. The rule is NON_COMPLIANT if the encryption is not enabled in the Persistent Volume configuration or if the specified encryption key does not match the expected key.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.16", "Description": "Checks if Kubernetes clusters are configured to have secrets encrypted. The rule is NON_COMPLIANT if a Kubernetes cluster does not have EncryptionConfiguration set, or if EncryptionConfiguration does not include 'secrets' as a resource.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.5.1.17", - "Description": "Verifies whether Kubernetes clusters in the Amazon Elastic Kubernetes Service (EKS) are set up to ensure that Kubernetes secrets are encrypted using AWS Key Management Service (KMS) keys.", - "Name": "Amazon Elastic Kubernetes Service (EKS)", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Amazon Elastic Kubernetes Service (EKS)" - } - ] - }, - { - "Id": "3.5.1.18", - "Description": "Checks if a Kubernetes StatefulSet has encryption-at-rest enabled for its persistent volume claims. The rule is NON_COMPLIANT if 'encryption' is disabled or if the storage class does not match the approvedStorageClasses parameter.", - "Name": "Kubernetes StatefulSet", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes StatefulSet" + "Service": "Core" } ] }, { "Id": "3.5.1.19", "Description": "Checks if Kubernetes clusters have encryption at rest configuration enabled for secrets. The rule is NON_COMPLIANT if the encryption configuration for secrets in the Kubernetes API server is not set.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -11811,1470 +11035,1434 @@ { "Id": "3.5.1.21", "Description": "Checks if Kubernetes persistent volumes are encrypted at rest with server-side encryption. The rule is NON_COMPLIANT for a persistent volume if 'encryption' is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.22", "Description": "Checks if storage encryption is enabled for your Kubernetes Persistent Volumes (PVs). The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.23", "Description": "Checks if a Kubernetes cluster has encrypted etcd storage. The rule is NON_COMPLIANT if the etcd storage used by the Kubernetes cluster is not encrypted.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, { "Id": "3.5.1.24", "Description": "Checks if Kubernetes clusters have encryption at rest configuration enabled for secrets. The rule is NON_COMPLIANT if the encryption of secrets at rest is not configured properly.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "3.5.1.25", - "Description": "Checks if a Kubernetes database (e.g., PostgreSQL, MySQL) deployed using a StatefulSet or Deployment has encryption at rest enabled. The rule is NON_COMPLIANT if the database storage (PersistentVolume) is not using encryption provided by the underlying storage class or cloud provider.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.26", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are using encryption at rest. The rule is NON_COMPLIANT if the Kubernetes Persistent Volumes do not have encryption enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.27", "Description": "Checks if encryption is enabled for Kubernetes Persistent Volumes (PVs). The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.28", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not configured for RBAC (Role-Based Access Control), or if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.5.1.29", "Description": "Checks if Kubernetes clusters are using a specified secret for encryption. The rule is COMPLIANT if encryption is enabled and the cluster uses the secret specified for encryption. The rule is NON_COMPLIANT if the cluster is not encrypted or encrypted with another secret.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.30", "Description": "Checks if your Kubernetes Persistent Volume (PV) is configured with encryption enabled at rest, or if the Persistent Volume claim (PVC) policy explicitly denies access to volumes that are not encrypted. The rule is NON_COMPLIANT if your Persistent Volume is not encrypted by default.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.5.1.31", "Description": "Checks if the Kubernetes Secrets are encrypted at rest. The rule is NON_COMPLIANT if the Secrets are not encrypted with a defined encryption provider.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.32", "Description": "Checks if a Kubernetes Secret containing encryption keys is configured for a specific Deployment. The rule is NON_COMPLIANT if 'encryptionKey' is not specified in the Deployment's environment variables.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.33", "Description": "Checks if a Kubernetes Secret is configured for a pod. The rule is NON_COMPLIANT if the pod does not specify a 'secret' volumne or environment variable referencing a Kubernetes Secret.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.34", "Description": "Checks if all Kubernetes Secrets are encrypted using a customer-managed key configured for the Kubernetes cluster or are not using the default encryption settings. The rule is COMPLIANT if a secret is encrypted using a customer-managed key; otherwise, it is NON_COMPLIANT if it uses the default encryption settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.5.1.35", "Description": "Checks if Kubernetes Secrets are encrypted using the configured encryption providers. The rule is NON_COMPLIANT if a Secret is not encrypted. Optionally, specify the encryption provider configuration for the rule to check.", - "Name": "Kubernetes Secrets", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "3.5.1: Primary account number (PAN) is secured wherever it is stored.", - "Service": "Kubernetes Secrets" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.1", "Description": "Checks if Kubernetes TLS secrets are due for renewal within the specified number of days. TLS secrets in Kubernetes may need to be manually renewed if they are not automatically managed. The rule is NON_COMPLIANT if your TLS secrets are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.2.2", "Description": "Checks if Kubernetes Cluster has a Certificate Authority (CA) that is disabled. The rule is NON_COMPLIANT for root CAs with status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.6.1.2.3", "Description": "Checks if an Ingress resource in Kubernetes uses a TLS certificate. The rule is NON_COMPLIANT if the Ingress resource does not have an associated TLS secret.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.5", "Description": "Checks if Kubernetes Ingress resources are configured to use TLS certificates from a trusted certificate provider. This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 rule configured without a TLS certificate or is configured with a certificate not from a trusted provider.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.6", "Description": "Checks if Ingress resources in Kubernetes use TLS certificates provided by a secret in Kubernetes. To use this rule, an Ingress resource should be configured with a TLS section that references the secret containing the TLS certificate. This rule is only applicable to Ingress configurations and does not apply to other services like NodePort or LoadBalancer services.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.7", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow blocked actions on Kubernetes Secrets. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes Secrets by the managed RBAC policy.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.6.1.2.8", "Description": "Checks if the Role-based Access Control (RBAC) policies applied to Kubernetes users, roles, and role bindings do not allow access to restricted actions on all Kubernetes resources. The rule is NON_COMPLIANT if any restricted action is permitted on all Kubernetes resources in a role or role binding.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.6.1.2.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion in the Kubernetes cluster. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1.2: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.3.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are about to expire within a specified number of days. Certificates can be automatically renewed if managed by cert-manager; however, manually imported certificates may not be renewed automatically. If the TLS certificates in Secrets are nearing expiration, the state is marked as NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.3.2", "Description": "Checks if Kubernetes Certificate Authority has a root CA that is disabled. The rule is NON_COMPLIANT for root CAs with a status that is not DISABLED.", - "Name": "Kubernetes Certificate Authority", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Certificate Authority" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.6.1.3.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS settings. The rule is NON_COMPLIANT if the Ingress resource does not have an associated TLS certificate.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.3.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.3.5", "Description": "Checks if Kubernetes Ingress resources are configured to use certificates from a certificate management service (e.g., cert-manager) for TLS termination. This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 rule that is configured without a TLS certificate or is configured with a non-approved certificate.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.3.6", "Description": "Checks if the Kubernetes Ingress resource uses SSL certificates provided by a Certificate Manager, such as cert-manager. To use this rule, an HTTPS or TLS-enabled Ingress must be configured. This rule is only applicable to Ingress resources and does not check services directly or other types of load balancers.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.3.7", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow blocked actions on Kubernetes secrets. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes secrets by the RBAC policy.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.6.1.3.8", "Description": "Checks if the role or service accounts in Kubernetes have permissions that allow actions on Kubernetes resources that should be restricted. The rule is NON_COMPLIANT if any disallowed action is permitted through a Role or ClusterRole in Kubernetes RBAC settings.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.6.1.3.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1.3: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.4.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are due for renewal within the specified number of days. Certificates managed by external certificate issuers, such as Cert-Manager, may automatically renew, while manually created secrets may require manual intervention. The status is NON_COMPLIANT if secrets with certificates are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.4.2", "Description": "Checks if Kubernetes CertificateSigningRequests (CSRs) have a root CA that is not in a valid state. The rule is NON_COMPLIANT for root CAs with status that is not 'Approved' or 'Pending'.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_csr_approval_access" ], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.6.1.4.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS. The rule is NON_COMPLIANT if the Ingress resource does not have an associated TLS secret.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.4.4", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.4.5", "Description": "Checks if Kubernetes Ingress resources have TLS configurations that use certificates from a trusted certificate management solution, such as cert-manager. This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 TLS configuration that is either missing a certificate or is configured with a certificate that is not managed by cert-manager.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.4.6", "Description": "Checks if Ingress resources in Kubernetes use SSL certificates provided by Kubernetes Secrets. To use this rule, ensure an Ingress resource is configured with an SSL or HTTPS backend. This rule is only applicable to Ingress configurations targeting HTTP routes and does not apply to ClusterIP or NodePort services.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "3.6.1.4.7", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow actions that are blocked on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes resources by the configured RBAC policies.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.6.1.4.8", "Description": "Checks if the role-based access control (RBAC) policies attached to your Kubernetes service accounts, roles, and role bindings do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in a RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes RBAC" - } - ] - }, - { - "Id": "3.6.1.4.9", - "Description": "Checks if Kubernetes secrets that are used for encryption (similar to AWS KMS keys) are not marked for deletion. The rule is NON_COMPLIANT if any Kubernetes secrets are marked for deletion.", - "Name": "Kubernetes Secrets", - "Checks": [], - "Attributes": [ - { - "Section": "3.6.1.4: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Secrets" + "Service": "API Server" } ] }, { "Id": "3.6.1.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are nearing expiration based on a specified time frame. Secrets can be renewed, but those manually created or managed may not have automatic renewal, leading to a NON_COMPLIANT status if they are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.6.1.2", "Description": "Checks if Kubernetes CertificateSigningRequests (CSR) have a root CA that is disabled. The rule is NON_COMPLIANT for CSRs with a status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_csr_approval_access" ], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.6.1.3", "Description": "Checks if a Kubernetes ingress resource is configured with an SSL certificate. The rule is NON_COMPLIANT if the ingress does not have an associated TLS secret for HTTPS endpoints.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is a default certificate. The rule is NON_COMPLIANT if an Ingress resource uses a default SSL certificate provided by the cloud provider.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.5", "Description": "Checks if Kubernetes Ingress resources have TLS configurations that use certificates from a trusted certificate authority, ensuring that at least one certificate from a valid source is associated with each Ingress. This rule is NON_COMPLIANT if at least one Ingress resource has a TLS configuration without a valid certificate or is configured with a certificate that is not from a trusted certificate authority.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.6", "Description": "Checks if Ingress resources in Kubernetes use SSL certificates provided by Kubernetes Secrets. To use this rule, an Ingress resource must be configured with an HTTPS backend. This rule is only applicable to Ingress resources and does not check Services of type LoadBalancer, ClusterIP, or NodePort.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.6.1.7", "Description": "Checks if the Kubernetes Role or ClusterRole do not allow blocked actions on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed by the Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "3.6.1.8", "Description": "Checks if the Role-based Access Control (RBAC) policies applied to your Kubernetes users, roles, and service accounts do not allow prohibited actions on all Kubernetes resources. The rule is NON_COMPLIANT if any prohibited action is allowed on any Kubernetes resource in an RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.6.1.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion in Kubernetes. The rule is NON_COMPLIANT if any Secrets are scheduled for deletion.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "3.6.1: Cryptographic keys used to protect stored account data are secured.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "3.7.1.1", "Description": "Checks if Kubernetes Secrets or Ingress resources containing TLS certificates are about to expire within the specified number of days. Certificates issued by external cert management tools (like CertManager) can be automatically renewed, but manually managed certificates require manual renewal. The rule is NON_COMPLIANT if any of your certificates are nearing expiration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.1.2", "Description": "Checks if RSA certificates managed by Kubernetes have a key length of at least '2048' bits. The rule is NON_COMPLIANT if the minimum key length is less than 2048 bits.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.1.3", "Description": "Checks if Kubernetes has a Certificate Authority (CA) that is disabled. The rule is NON_COMPLIANT for root CAs with a status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.7.1.4", "Description": "Checks if a Kubernetes Ingress resource has an associated TLS secret for SSL termination. The rule is NON_COMPLIANT if the Ingress resource does not reference a TLS secret.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.1.5", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default certificate. The rule is NON_COMPLIANT if an Ingress uses the default TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.1.6", "Description": "Checks if Kubernetes Ingress resources have TLS configurations that are using certificates from a certificate management solution, like Cert-Manager. This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 TLS configuration that is not using a certificate from the managed solution or is configured with a certificate that is not managed.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.1.7", "Description": "Checks if Kubernetes Ingress resources use SSL certificates provided by a Certificate Authority (e.g., Let's Encrypt) or Kubernetes secrets. To use this rule, configure a TLS section in your Ingress resource. This rule is only applicable to Ingress resources using SSL termination. This rule does not check other service types like NodePort or LoadBalancer services.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.1.8", "Description": "Checks if the managed Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow forbidden actions on Kubernetes resources. The rule is NON_COMPLIANT if any forbidden action is allowed on Kubernetes resources by the managed RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.7.1.9", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, roles, and role bindings do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in a RBAC policy.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.7.1.10", "Description": "Checks if Kubernetes Secrets are not marked for deletion in Kubernetes. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.1: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.2.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are nearing expiration based on a specified threshold of days. Kubernetes does not automatically renew certificates unless managed by an external controller like cert-manager. The status is NON_COMPLIANT if any managed certificates are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.2.2", "Description": "Checks if Kubernetes CertificateSigningRequest (CSR) has a root certificate that is not marked as revoked. The rule is NON_COMPLIANT for CSRs with a status that is not REVOKED.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_csr_approval_access" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.7.2.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS and an associated SSL certificate. The rule is NON_COMPLIANT if the Ingress resource does not have TLS configured or lacks a valid SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.2.4", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is a default SSL certificate. The rule is NON_COMPLIANT if an Ingress uses the default TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.2.5", "Description": "Checks if Kubernetes Services of type LoadBalancer have TLS configured with Secrets that contain certificates from Kubernetes Secret Management. This rule is NON_COMPLIANT if at least 1 LoadBalancer service has at least 1 listener that is configured without a TLS Secret or is configured with a TLS Secret that does not contain a valid certificate.", - "Name": "Kubernetes LoadBalancer Services", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes LoadBalancer Services" + "Service": "API Server" } ] }, { "Id": "3.7.2.6", "Description": "Checks if Ingress controllers use SSL certificates provided by Kubernetes Secrets. To use this rule, ensure that Ingress resources are configured with TLS settings. This rule is only applicable to Ingress controllers. This rule does not check Services or other types of load balancing like NodePort.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "3.7.2.7", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow forbidden actions on Kubernetes resources. The rule is NON_COMPLIANT if any forbidden action is permitted on Kubernetes resources by the managed RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.7.2.8", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, roles, and clusters do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in a policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "3.7.2.9", "Description": "Checks if Kubernetes Secrets are not set for deletion. The rule is NON_COMPLIANT if Secrets are marked for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "3.7.2: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.4.1", "Description": "Checks if Kubernetes TLS Secrets in your namespace are marked for expiration within the specified number of days. TLS Certificates managed within Kubernetes can be set for automatic renewal using tools like cert-manager. The rule is NON_COMPLIANT if your TLS secrets are about to expire.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.7.4.2", "Description": "Checks if Kubernetes has a Certificate Signing Request (CSR) approved that is not in a terminal state. The rule is NON_COMPLIANT for CSRs that are not approved or rejected.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.4.3", "Description": "Checks if a Kubernetes Ingress resource has TLS configured. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS secret for SSL termination.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.4.4", "Description": "Checks if the TLS certificate associated with an Ingress resource in Kubernetes is a default or autogenerated certificate. The rule is NON_COMPLIANT if an Ingress resource is using a default or autogenerated TLS certificate instead of a managed or custom TLS certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.4.5", "Description": "Checks if automatic key rotation is enabled for each key and matches to the key ID of the customer created Kubernetes Secret. The rule is NON_COMPLIANT if the Kubernetes ServiceAccount role for a resource does not have the ability to get and describe Secrets.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_service_account_private_key_file" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.7.4.6", "Description": "Checks if Kubernetes Services of type LoadBalancer have TLS settings configured with certificates from a specified secret. This rule is NON_COMPLIANT if at least 1 LoadBalancer service has at least 1 listener that is configured without a valid TLS secret or is configured with a certificate different from the specified one.", - "Name": "LoadBalancer Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "LoadBalancer Service" + "Service": "API Server" } ] }, { "Id": "3.7.4.7", "Description": "Checks if the Ingress resources in Kubernetes use TLS certificates provided by Kubernetes Secrets. To use this rule, configure an Ingress resource with TLS settings using the appropriate Secret. This rule is only applicable to Ingress resources and does not apply to Services or other types of Load Balancers.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.4.8", "Description": "Checks if the managed Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow blocked actions on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes resources by the managed RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.7.4.9", "Description": "Checks if the Role policies attached to your Kubernetes service accounts do not allow actions that are restricted on all cluster resources. The rule is considered NON_COMPLIANT if any restricted action is allowed in the Role binding policies.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.7.4.10", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.4: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.5.1", "Description": "Checks if Kubernetes TLS Secrets in your cluster are marked for expiration within the specified number of days. TLS Secrets in Kubernetes must be manually renewed; Kubernetes does not automatically renew them. The rule is NON_COMPLIANT if your TLS Secrets are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.5: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.5.2", "Description": "Verifies if automatic key rotation is enabled for each key and matches to the key ID of the customer created Kubernetes Secret. The rule is NON_COMPLIANT if the Service Account for a resource does not have the required permissions to manage Secrets.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.5: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.6.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are nearing expiration based on specified threshold. Kubernetes does not automatically renew imported certificates unless managed through an appropriate controller. The rule is NON_COMPLIANT if any certificates are about to expire.", - "Name": "Kubernetes", + "Name": "KUBELET", "Checks": [ "kubelet_rotate_certificates" ], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "KUBELET" } ] }, { "Id": "3.7.6.2", "Description": "Checks if Kubernetes has a CertificateSigningRequest (CSR) that is approved. The rule is NON_COMPLIANT for CSRs that are not approved.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_csr_approval_access" ], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.7.6.3", "Description": "Checks if a Kubernetes Ingress resource uses TLS for secure connections. The rule is NON_COMPLIANT if the Ingress resource does not have an associated TLS secret.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.6.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is using the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.6.5", "Description": "Checks if Kubernetes Services of type LoadBalancer have configured TLS termination using certificates from a trusted certificate management solution (e.g. cert-manager). This rule is NON_COMPLIANT if at least 1 LoadBalancer service has at least 1 listener that is configured without a TLS certificate or is configured with a certificate that is not from a trusted source.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "API Server" } ] }, { "Id": "3.7.6.6", "Description": "Checks if Kubernetes Ingress resources utilize TLS secrets for SSL termination. To use this rule, ensure that Ingress is configured with TLS settings. This rule is only applicable to Ingress resources and does not check services that do not involve SSL termination.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.6.7", "Description": "Verifies that the Kubernetes Role-Based Access Control (RBAC) policies do not permit actions that are disallowed by the cluster's security context. The rule is NON_COMPLIANT if any disallowed actions are permitted by the Kubernetes RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "3.7.6.8", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, roles, and role bindings do not allow blocked actions on all Kubernetes secrets. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes secrets in an RBAC policy.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.7.6.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.6: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "3.7.7.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates in your cluster are about to expire within the specified number of days. Certificates issued by Kubernetes can be automatically renewed with appropriate configurations, but manually imported certificates may require manual renewal. The rule is NON_COMPLIANT if your secrets (certificates) are approaching expiration.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "3.7.7.2", "Description": "Checks if Kubernetes CA (Certificate Authority) has a root CA that is disabled. The rule is NON_COMPLIANT for root CAs with status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.7.7.3", "Description": "Checks if a Kubernetes Ingress resource is configured with TLS. The rule is NON_COMPLIANT if the Ingress does not have a TLS secret associated with it for secure connections.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.7.4", "Description": "Checks if the certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.7.5", "Description": "Checks if Kubernetes Services of type LoadBalancer have annotations that specify certificates from a certificate manager (like Cert-Manager). This rule is NON_COMPLIANT if at least 1 Service of type LoadBalancer has an annotation configured without a valid certificate reference or is configured with a certificate different from a managed certificate.", - "Name": "Kubernetes Services", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_rotate_kubelet_server_cert" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes Services" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "3.7.7.6", "Description": "Checks if Ingress resources in Kubernetes are using TLS/SSL certificates managed by Kubernetes secrets. To use this rule, an Ingress must be configured with TLS settings. This rule is only applicable to Ingress resources and does not check LoadBalancer services or NodePort services.", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "3.7.7.7", "Description": "Checks if the Kubernetes RBAC (Role-Based Access Control) policies that you create do not allow blocked actions on Kubernetes objects. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes objects by the defined RBAC policies.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "3.7.7.8", "Description": "Checks if the Role-Based Access Control (RBAC) policies attached to your Kubernetes users, service accounts, and roles do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in a role or cluster role.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "3.7.7.9", "Description": "Checks if Kubernetes Secrets are not marked for deletion. The rule is NON_COMPLIANT if Secrets are scheduled for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "3.7.7: Where cryptography is used to protect stored account data, key management processes and procedures covering all aspects of the key lifecycle are defined and implemented.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.1", "Description": "Checks if Kubernetes Secrets containing TLS certificates are marked for expiration within the specified number of days. Auto-generated certificates by a CertificateIssuer or a CertificateManagement controller are usually auto-renewed. User-managed certificates need manual renewal. The rule is NON_COMPLIANT if your secrets are about to expire.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.2", "Description": "Checks if a Kubernetes Cluster has a Root Certificate Authority (CA) that is disabled. The rule is NON_COMPLIANT for Root CAs with a status that is not DISABLED.", - "Name": "Kubernetes", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_root_ca_file_set" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "4.2.1.1.3", "Description": "Checks if HTTP to HTTPS redirection is configured on all Ingress resources in Kubernetes. The rule is NON_COMPLIANT if one or more Ingress resources do not have a redirect from HTTP to HTTPS configured. The rule is also NON_COMPLIANT if one or more Ingress resources are forwarding traffic to an HTTP service instead of redirecting to HTTPS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.4", "Description": "Checks if a Kubernetes Ingress resource is configured with an SSL certificate. The rule is NON_COMPLIANT if the Ingress resource does not have an associated TLS secret for SSL termination.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.5", "Description": "Checks if the TLS certificate associated with a Kubernetes Ingress resource is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.6", "Description": "Checks if Kubernetes Ingress is using deprecated SSL protocols for HTTPS communication between Ingress controllers and backend services. This rule is NON_COMPLIANT for an Ingress resource if any 'tls' specifications include 'SSLv3'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.7", "Description": "Checks if Kubernetes Ingress resources are encrypting traffic to backend services. The rule is NON_COMPLIANT if 'backend.servicePort' is configured for non-SSL (HTTP) traffic or if 'backend.servicePort' is configured for SSL traffic and 'spec.tls' is not properly set up for secure communication with the backend services.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.8", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS by verifying that the nginx.ingress.kubernetes.io/ssl-redirect annotation is set to 'true'. The rule is NON_COMPLIANT if this annotation is not present or set to 'false'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.9", "Description": "Checks if your Kubernetes cluster has network policies applied to ensure that traffic between pods is encrypted using TLS. The rule is NON_COMPLIANT if a pod communication does not enforce TLS encryption.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.10", "Description": "Checks if Kubernetes database connections are configured with SSL. The rule is NON_COMPLIANT if the database does not have SSL enabled for connections.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "4.2.1.1.11", - "Description": "Checks if Kubernetes StatefulSets for Redis data stores are configured to use TLS/SSL for secure communication between Pods. The rule is NON_COMPLIANT if TLS/SSL encryption is not enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.12", "Description": "Checks if Kubernetes Redis pods have encryption-in-transit enabled. The rule is NON_COMPLIANT for a Redis pod if 'encryption-in-transit' is not configured or set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -13293,132 +12481,132 @@ { "Id": "4.2.1.1.14", "Description": "Checks if Kubernetes Services of type LoadBalancer have HTTPS configured with trusted TLS certificates, ensuring that at least 1 Service does not have a valid certificate issued by a trusted Certificate Authority or is misconfigured with a certificate that is not trusted.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.15", "Description": "Checks if the Ingress resources in Kubernetes use TLS certificates provided by a Certificate Management solution (like cert-manager). To apply this rule, use an Ingress resource configured with TLS settings. This rule is not applicable to Services without Ingress or other types of Load Balancers (like NodePort or ClusterIP).", - "Name": "Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.16", "Description": "Checks whether your Kubernetes Ingress resources are using a custom TLS configuration. The rule is only applicable if there are TLS-enabled Ingress resources.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.17", "Description": "Checks if your Kubernetes Ingress resources have SSL/TLS configurations that use a predefined policy. The rule is NON_COMPLIANT if the Ingress TLS settings do not match the specified 'predefinedPolicyName'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.18", "Description": "Checks if your Kubernetes Service is configured with TLS termination or HTTPS endpoints. The rule is NON_COMPLIANT if a Service does not have TLS settings configured.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.19", "Description": "Checks if Kubernetes clusters have NetworkPolicies implemented. The rule is NON_COMPLIANT if there are no NetworkPolicies applied to the namespace or the existing NetworkPolicies do not satisfy the specified rule parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.20", "Description": "Checks if the Kubernetes Role or ClusterRole permissions do not allow blocked actions on Secrets. The rule is NON_COMPLIANT if any blocked action is allowed on Secrets by the Kubernetes Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "4.2.1.1.21", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, service accounts, and roles do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all resources in an RBAC policy.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "4.2.1.1.22", "Description": "Checks if Kubernetes Secrets are not marked for deletion and are actively usable. The rule is NON_COMPLIANT if any Secrets are marked for deletion.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.1.23", "Description": "Checks if a Kubernetes cluster enforces encryption in transit for communication between services using TLS. The rule is NON_COMPLIANT if plain text communication is enabled for service-to-service connections in the cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -13437,14 +12625,14 @@ { "Id": "4.2.1.1.25", "Description": "Check if Kubernetes cluster nodes have encryption enabled for communication between them. The rule is NON_COMPLIANT if the encryption for communication between nodes is not enabled.", - "Name": "Kubernetes", + "Name": "KUBELET", "Checks": [ "kubelet_strong_ciphers_only" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "KUBELET" } ] }, @@ -13463,110 +12651,98 @@ { "Id": "4.2.1.1.27", "Description": "Checks if Kubernetes services have policies that require requests to use HTTPS. The rule is NON_COMPLIANT if any service is configured to allow HTTP requests.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "4.2.1.1", "Description": "Checks if all Ingress resources have configured HTTP to HTTPS redirection. The rule is NON_COMPLIANT if one or more Ingress resources do not have HTTP to HTTPS redirection in place or if any Ingress resources forward traffic to an HTTP service instead of redirecting it.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.2", "Description": "Checks if Kubernetes Ingress resources are using deprecated SSL protocols for HTTPS communication between Ingress controllers and backend services. This rule is NON_COMPLIANT for an Ingress resource if any 'sslProtocols' includes 'SSLv3'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.3", "Description": "Checks if Kubernetes Ingress resources are enforcing secure communication; the rule is NON_COMPLIANT if the Ingress resource allows 'HTTP' traffic or if it has 'RedirectToHttps' disabled for HTTP routes.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.4", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS. The rule is NON_COMPLIANT if the Ingress resource allows HTTP traffic without a redirect to HTTPS.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.5", "Description": "Checks if your Kubernetes cluster has network policies applied to ensure that traffic between pods is encrypted using TLS. The rule is NON_COMPLIANT if a pod does not have TLS encryption for network communication.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.6", "Description": "Checks if Kubernetes database connection settings are configured with SSL. The rule is NON_COMPLIANT if the database connection does not have SSL configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.7", "Description": "Checks if Kubernetes Secrets for Redis data stores are encrypted at rest. The rule is NON_COMPLIANT if encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "4.2.1.8", - "Description": "Checks if Kubernetes StatefulSets have encryption in transit enabled. The rule is NON_COMPLIANT for a StatefulSet if 'spec.template.spec.containers.ports[].protocol' is not set to 'TLS'.", - "Name": "StatefulSet", - "Checks": [], - "Attributes": [ - { - "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "StatefulSet" + "Service": "Core" } ] }, @@ -13585,76 +12761,76 @@ { "Id": "4.2.1.10", "Description": "Checks if the Ingress resources use SSL certificates provided by Kubernetes Secrets or external cert-manager. To use this rule, ensure that an SSL or HTTPS listener is configured in the Ingress resource. This rule is only applicable to Ingress controllers like NGINX Ingress Controller and Traefik. This rule does not check other types of services or load balancers.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "4.2.1.11", "Description": "Checks whether your Kubernetes Ingress resources with TLS configurations are using a custom TLS policy. The rule is only applicable if there are Ingress resources configured with TLS.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.12", "Description": "Checks if your Kubernetes Ingress resources use a predefined TLS configuration. The rule is NON_COMPLIANT if the Ingress TLS configuration does not equal the value of the parameter 'predefinedTLSConfig'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "4.2.1.13", "Description": "Checks if your Kubernetes Service is configured with HTTPS or TLS termination. The rule is NON_COMPLIANT if a Service does not have HTTPS or TLS configured.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "4.2.1.14", "Description": "Checks if Kubernetes clusters have Network Policies enabled. The rule is NON_COMPLIANT if a Network Policy is not applied to the namespace or the Network Policy does not satisfy the specified rule parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.15", "Description": "Checks if a Kubernetes cluster enforces encryption in transit for communications between pods using TLS. The rule is NON_COMPLIANT if plain text communication is enabled for in-cluster pod-to-pod connections.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -13673,470 +12849,446 @@ { "Id": "4.2.1.17", "Description": "Check if Kubernetes pods have encrypted communication between them. The rule is NON_COMPLIANT if the network policies that enforce pod-to-pod encryption are not implemented.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.18", "Description": "Checks if Kubernetes clusters require TLS/SSL encryption for communication with SQL clients. The rule is NON_COMPLIANT if any Kubernetes SQL client connection does not have TLS/SSL enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "4.2.1.19", "Description": "Checks if Kubernetes Ingress resources have annotations enforcing HTTPS and preventing HTTP traffic. The rule is NON_COMPLIANT if any Ingress resource allows HTTP traffic without redirection to HTTPS.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "4.2.1: PAN is protected with strong cryptography during transmission.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if 'accessLog' annotations are not present in the Ingress configuration.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.2", "Description": "Checks if all methods in Kubernetes Ingress resources have access logging enabled by validating the configuration of the Ingress controller. The rule is NON_COMPLIANT if access logging is not enabled, or if the log level is neither ERROR nor INFO.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.3", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Ingress controllers. The rule is COMPLIANT if OpenTelemetry tracing is enabled and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.4", "Description": "Checks if a Kubernetes API (such as an Agones or custom resource-based API) has logging enabled. The rule is NON_COMPLIANT if logging is not enabled, or 'logLevel' is neither ERROR nor ALL.", - "Name": "Kubernetes API", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes API" + "Service": "API Server" } ] }, { "Id": "5.3.4.5", "Description": "Checks if Services of type LoadBalancer in Kubernetes are configured with user-defined health check settings. The rule is NON_COMPLIANT if the health check settings do not match the user-defined configurations.", - "Name": "Kubernetes LoadBalancer Service", + "Name": "Scheduler", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes LoadBalancer Service" + "Service": "Scheduler" } ] }, { "Id": "5.3.4.6", "Description": "Checks if Kubernetes Ingress resources are configured to log access to a specified logging service. The rule is NON_COMPLIANT if an Ingress resource does not have logging configured.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.7", "Description": "Checks if at least one Kubernetes audit policy is logging requests to all namespaces. The rule is NON_COMPLIANT if there are no audit policies or if audit policies do not log S3-like storage access events.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.8", "Description": "Checks that there is at least one Kubernetes audit policy defined that follows security best practices. This rule is COMPLIANT if there is at least one audit policy that meets all of the following criteria specified for security configurations.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "5.3.4.9", - "Description": "The rule identifier is CLOUD_TRAIL_ENABLED, and the rule name is cloudtrail-enabled, which indicates that there is a difference between the identifier used for internal processing and the user-friendly name displayed.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "AWS CloudTrail" + "Service": "API Server" } ] }, { "Id": "5.3.4.10", "Description": "Checks if a Kubernetes Pod has at least one logging mechanism enabled. The rule is NON_COMPLIANT if all logging configurations for the Pod are set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.11", "Description": "Checks if a Kubernetes logging configuration (e.g., Fluentd, Elasticsearch) has a log retention policy set to retain logs for more than 365 days or a specified retention period. The rule is NON_COMPLIANT if the retention period is less than MinRetentionTime, if specified, or else 365 days.", - "Name": "Kubernetes Logging", + "Name": "API Server", "Checks": [ "apiserver_audit_log_maxage_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Logging" + "Service": "API Server" } ] }, { "Id": "5.3.4.12", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes Pod events. The rule is NON_COMPLIANT if logging is not enabled or Pod logging of a Kubernetes cluster has a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.13", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.14", "Description": "Checks if the Kubernetes cluster has logging enabled for client connections to the API server. The rule is NON_COMPLIANT if 'apiserver-logging.enabled' is set to false.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "5.3.4.15", "Description": "Checks if logging configuration is set on active Kubernetes Pod specifications. This rule is NON_COMPLIANT if an active Pod does not have a log configuration defined or if the logging configuration is set to null in at least one container definition.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.16", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for the Kubernetes clusters is not enabled for all log types, such as audit logs, controller logs, and application logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.17", "Description": "Checks if Kubernetes clusters are configured to send logs to a centralized logging system like Elasticsearch or a logging stack such as EFK (Elasticsearch, Fluentd, Kibana). The rule is COMPLIANT if logging is enabled and set up for the pods in the Kubernetes cluster. This rule is NON_COMPLIANT if logging is not configured properly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.18", "Description": "Checks if Kubernetes pods are configured to send logs to a specified logging solution (e.g., Fluentd, Elasticsearch). The rule is NON_COMPLIANT if pod logging is not enabled or misconfigured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.19", "Description": "Checks if the Kubernetes Ingress resource has access logging enabled by examining if the specified logging annotation is set to true. The rule is NON_COMPLIANT if the access logs are not enabled or the logging destination does not match the defined S3 bucket.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "5.3.4.20", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled for the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.21", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "5.3.4.22", - "Description": "In Kubernetes, a similar rule could be represented by a custom resource definition (CRD) for enforcing multi-region logging, which ensures that logs from multiple regions are collected in a centralized manner. The rule identifier (MULTI_REGION_LOGGING_ENABLED) and rule name (multi-region-logging-enabled) would be analogous, where the identifier varies from the name.", - "Name": "Logging", - "Checks": [], - "Attributes": [ - { - "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Logging" + "Service": "API Server" } ] }, { "Id": "5.3.4.23", "Description": "Checks if a Kubernetes cluster has logging enabled for auditing. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.24", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "5.3.4.25", "Description": "Checks if Kubernetes clusters have audit logging enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.26", "Description": "Checks if Kubernetes clusters are configured to send logs to a logging system (e.g., Elasticsearch, Fluentd, or a similar logging service). The rule is NON_COMPLIANT if logging is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.27", "Description": "Checks if Kubernetes clusters are configured to publish logs to a centralized logging system (e.g., Elasticsearch or Fluentd). The rule is NON_COMPLIANT if clusters do not have logging configured to publish logs appropriately.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.28", "Description": "Checks if the logging for Kubernetes pods is enabled. The rule is NON_COMPLIANT if any pod logs are not being captured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.29", "Description": "Checks if Kubernetes clusters are logging audits to a specific location. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'logDestination' parameter is provided but the audit logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "5.3.4.30", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not encrypted or encrypted with another key, or if the cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.31", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled for CoreDNS.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "5.3.4.32", "Description": "Checks if logging is enabled for your Kubernetes Pods. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "5.3.4.33", "Description": "Checks if a Kubernetes Pod has logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging enabled or the logging configuration is not at the minimum level provided.", - "Name": "Kubernetes Pod", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Pod" + "Service": "Core" } ] }, { "Id": "5.3.4.34", "Description": "Checks if Kubernetes Network Policies are implemented and enforce traffic control between pods. The rule is NON_COMPLIANT if Network Policies are not applied to at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -14155,72 +13307,72 @@ { "Id": "5.3.4.36", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource, if it does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "5.3.4: Anti-malware mechanisms and processes are active, maintained, and monitored.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.3.3.1", "Description": "Validates the installation of specified applications on a Kubernetes pod, with optional minimum version requirements and platform constraints.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.3.3.2", "Description": "Checks if the compliance status of the Kubernetes cluster's node patch compliance is up-to-date or not after applying patches. The rule is compliant if the field status is 'COMPLIANT'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.3.3.3", "Description": "Checks if Kubernetes Pods are using the latest container image version. The rule is NON_COMPLIANT if the image tag in the Pod specification is not set to 'latest', or if no specific image version is provided in the deployment manifest.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.3.3.4", "Description": "Checks if a Kubernetes cluster is running the oldest supported version. The rule is NON_COMPLIANT if the Kubernetes cluster is running the oldest supported version (equal to the parameter 'oldestVersionSupported').", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.3.3.5", "Description": "Checks if a Kubernetes cluster is running a supported version. This rule is NON_COMPLIANT if the cluster is running an unsupported version (less than the parameter 'oldestVersionSupported').", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -14251,422 +13403,410 @@ { "Id": "6.3.3.8", "Description": "Checks if the Kubernetes Pod specifications for image, service account, restart policy, and resource limits match the expected values. The rule ignores Pods with the 'initContainers' field defined and Pods with a restart policy set to 'Never'. The rule is NON_COMPLIANT if the Pod specifications do not match the expected values.", - "Name": "Kubernetes Pods", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes Pods" + "Service": "RBAC" } ] }, { "Id": "6.3.3.9", "Description": "Checks if Kubernetes cluster version updates are available but not installed. The rule is NON_COMPLIANT for a Kubernetes cluster if the latest software updates are not installed.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "6.3.3.10", - "Description": "Checks if Kubernetes pods using the PersistentVolumeClaim (PVC) are configured for automatic updates. The rule is NON_COMPLIANT if the value of 'automaticUpdates' is false.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.3.3.11", "Description": "Checks if Kubernetes clusters have the specified maintenance settings. The rule is NON_COMPLIANT if automatic upgrades to new Kubernetes versions are disabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.3.3: Security vulnerabilities are identified and addressed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.4.1.1", "Description": "Checks if Kubernetes Ingress has security policies enforced. The rule is NON_COMPLIANT if key: ingress.policy.enabled is set to false.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.1.2", "Description": "Checks if a Kubernetes Ingress resource is using a specified NGINX Ingress Controller with appropriate annotations for web access control. The rule is NON_COMPLIANT if no NGINX Ingress Controller is specified or if the annotations do not match the predefined rules.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.1.3", "Description": "Checks if Kubernetes APIs are associated with Network Policies. The rule is NON_COMPLIANT for a Kubernetes API if it is not associated with a Network Policy.", - "Name": "Kubernetes API", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes API" + "Service": "API Server" } ] }, { "Id": "6.4.1.4", "Description": "Checks if Kubernetes Ingress resources are associated with Network Policies for traffic control. The rule is NON_COMPLIANT if an Ingress resource is not associated with a Network Policy.", - "Name": "Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.1.5", "Description": "Checks if the Network Policy is associated with an Ingress resource managing traffic to services or an Ingress Controller service. When a management tool creates this rule, the policy owner specifies the NetworkPolicy in the resource definition and can optionally enable remediation actions.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.1.6", "Description": "Verifies that the Network Policies are associated with the Ingress Controller in the correct order of priority. The priority is determined by the rank of the Network Policies in the policy parameter. When a Kubernetes Networking policy is created, its priority is assigned based on its order in the list, starting from the highest priority. The cluster administrator specifies the Network Policies rank and can optionally enable custom actions.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "6.4.1.7", "Description": "Checks if Kubernetes Network Policies contain ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined in a Network Policy.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "6.4.1.8", "Description": "Checks if a Kubernetes Network Policy contains any ingress or egress rules. This rule is NON_COMPLIANT if a Network Policy does not contain any ingress or egress rules.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.4.1.9", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.1.10", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if no rules are defined within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.1.11", "Description": "Checks whether a Kubernetes NetworkPolicy contains any ingress or egress rules. This rule is NON_COMPLIANT if a NetworkPolicy does not contain any rules.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.1.12", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the NetworkPolicy.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.1.13", "Description": "Checks whether a Kubernetes NetworkPolicy contains at least one ingress or egress rule. This policy is COMPLIANT if it contains at least one rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.1.14", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no ingress or egress rules present within the NetworkPolicy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.1: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.4.2.1", "Description": "Checks if Kubernetes Network Policies are enabled on Ingress Controllers. The rule is NON_COMPLIANT if the key: networkPolicies.enabled is set to false.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "6.4.2.2", "Description": "Checks if a Kubernetes Ingress resource is using a valid NetworkPolicy or an Ingress controller with proper security configurations. The rule is NON_COMPLIANT if a NetworkPolicy is not used or if the used NetworkPolicy does not match what is recommended in the policy specifications.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.2.3", "Description": "Checks if Kubernetes APIs are associated with Network Policies. The rule is NON_COMPLIANT for a Kubernetes API if it is not associated with a Network Policy.", - "Name": "Kubernetes API", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes API" + "Service": "API Server" } ] }, { "Id": "6.4.2.4", "Description": "Checks if Kubernetes Ingress resources are associated with any Network Policies to ensure security. The rule is NON_COMPLIANT if an Ingress resource is not associated with any Network Policy.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.2.5", "Description": "Checks if the NetworkPolicy is associated with a Service or Ingress resource in Kubernetes. When a NetworkPolicy is created, the policy owner specifies the namespace and selectors that determine which pods are affected by the policy and can optionally enable actions for traffic management.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.2.6", "Description": "Verifies that the NetworkPolicy objects associated with a Kubernetes Ingress resource have the correct priority, based on the rank specified in the NetworkPolicy. The Kubernetes system assigns priorities in increasing order, starting from the highest priority (0) and continuing with 1, 2, and so on. The cluster administrator defines the rank in the NetworkPolicy and can optionally enable remediation actions.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "6.4.2.7", "Description": "Checks if Kubernetes Network Policies contain rules. The policy is NON_COMPLIANT if there are no rules in a Kubernetes Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "6.4.2.8", "Description": "Checks if a Kubernetes Network Policy contains any ingress or egress rules. This rule is NON_COMPLIANT if a Network Policy does not contain any ingress or egress rules.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "6.4.2.9", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The NetworkPolicy is NON_COMPLIANT if there are no rules present within the policy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.2.10", "Description": "Checks if a Kubernetes NetworkPolicy contains any rules. The NetworkPolicy is NON_COMPLIANT if no rules are present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.2.11", "Description": "Checks whether a Kubernetes NetworkPolicy contains any ingress or egress rules. This policy is NON_COMPLIANT if a NetworkPolicy does not contain any ingress or egress rules.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "6.4.2.12", "Description": "Checks if Kubernetes NetworkPolicies contain any rules. The policy is NON_COMPLIANT if there are no rules present within a Kubernetes NetworkPolicy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.4.2.13", "Description": "Checks whether a Kubernetes Network Policy contains at least one ingress or egress rule. This policy is COMPLIANT if it contains at least one rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "6.4.2.14", "Description": "Checks if a Kubernetes Network Policy contains any rules. The policy is NON_COMPLIANT if there are no rules defined within the Network Policy.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.4.2: Public-facing web applications are protected against attacks.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "6.5.5.1", "Description": "Checks if the Kubernetes Deployment for a specific application is not using the default update strategy. The rule is NON_COMPLIANT if the Deployment is using the rolling update strategy with maxUnavailable set to 0.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.5.5: Changes to all system components are managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.5.5.2", "Description": "Checks if the first deployment stage of Kubernetes performs more than one deployment. Optionally checks if each of the subsequent remaining stages deploy to more than the specified number of deployments (deploymentLimit).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.5.5: Changes to all system components are managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "6.5.6.1", "Description": "Checks if the Kubernetes Deployment is not using the default rollout strategy. The rule is NON_COMPLIANT if the deployment strategy is set to 'Recreate'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "6.5.6: Changes to all system components are managed securely.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -14685,228 +13825,228 @@ { "Id": "7.2.1.1", "Description": "Checks if a Kubernetes cluster node is part of a specific Kubernetes Namespace. The rule is NON_COMPLIANT if the node is not part of the specified Namespace or if the Namespace does not match rule parameter NamespaceName.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.2", "Description": "Checks if a Kubernetes namespace has an attached Role or ClusterRole that prevents deletion of Pods. The rule is NON_COMPLIANT if the namespace does not have a Role/ClusterRole or has Roles/ClusterRoles without a suitable 'Deny' statement (like 'delete' permission for 'pods').", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.3", "Description": "Checks if a Kubernetes Pod security context has privileged mode enabled. The rule is NON_COMPLIANT for a Pod if 'privileged' is set to 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.4", "Description": "Checks if custom Kubernetes CustomResourceDefinitions (CRDs) have a role-based access control (RBAC) policy attached. The rule is NON_COMPLIANT for custom CRDs without an RBAC policy attached.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.5", "Description": "Checks if a Kubernetes pod has a Service Account attached to it. The rule is NON_COMPLIANT if no Service Account is attached to the pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.6", "Description": "Checks if the securityContext.privileged field in the Pod specification is set to 'true'. The rule is NON_COMPLIANT if the privileged field is 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.7", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the Pod's securityContext is set to 'false'.", - "Name": "Kubernetes Pods", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes Pods" + "Service": "Core" } ] }, { "Id": "7.2.1.8", "Description": "Checks if Kubernetes Pod specifications specify a user to run containers. The rule is NON_COMPLIANT if the 'securityContext.runAsUser' parameter is not present or set to '0'.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.9", "Description": "Verifies that the Kubernetes Role and ClusterRole policies do not authorize actions that are restricted on Kubernetes Secrets. The rule is NON_COMPLIANT if any restricted action is permitted on Kubernetes Secrets by the defined Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.10", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, roles, and groups do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is permitted on all Kubernetes resources in the RBAC policy.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.11", "Description": "Checks if the Kubernetes Role or ClusterRole resources do not have any permissions granted through inline policies. The rule is NON_COMPLIANT if a Kubernetes user, service account, or group has any permissions granted through inline Roles or ClusterRoles.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.12", "Description": "Checks in each Kubernetes Role or ClusterRole resource if a RoleBinding or ClusterRoleBinding is associated with the specified Role or ClusterRole. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding references the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.13", "Description": "Checks whether a Kubernetes Role or ClusterRole is bound to a ServiceAccount, or a RoleBinding or ClusterRoleBinding is associated with a User or Group that has one or more members.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.14", "Description": "Checks if Kubernetes Role or ClusterRole resources grant permissions that allow all actions on all resources. The rule is NON_COMPLIANT if any Role or ClusterRole definition includes rules with 'verbs' that list '*' for all actions over 'resourceNames' that include '*'.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.15", "Description": "Checks if Kubernetes Role-based Access Control (RBAC) rules that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole allows full access to at least 1 Kubernetes resource or namespace.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.2.1.16", "Description": "Checks if all required Kubernetes Roles or ClusterRoles specified in the list are attached to the ServiceAccount. The rule is NON_COMPLIANT if any required Role or ClusterRole is not attached to the ServiceAccount.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.17", "Description": "Checks if the Kubernetes root user (or equivalent admin user) has any access keys available. The result is COMPLIANT if no access keys are found. Otherwise, it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -14925,312 +14065,312 @@ { "Id": "7.2.1.19", "Description": "Checks if none of your Kubernetes ServiceAccounts have RoleBindings or ClusterRoleBindings directly attached. ServiceAccounts must inherit permissions from Roles or ClusterRoles. The rule is NON_COMPLIANT if there is at least one RoleBinding or ClusterRoleBinding directly attached to the ServiceAccount.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.20", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.21", "Description": "Checks if Kubernetes namespaces have Role-Based Access Control (RBAC) policies enabled. The rule is NON_COMPLIANT if RoleBindings are not present for the specified Kubernetes namespace.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.22", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.23", "Description": "Checks if a Kubernetes database instance, such as a PostgreSQL or MySQL deployment, has Role-Based Access Control (RBAC) authentication enabled. The rule is NON_COMPLIANT if the database instance does not have RBAC authentication enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.1.24", "Description": "Checks if Kubernetes Persistent Volumes (PVs) allow user permissions through access control lists (ACLs). The rule is NON_COMPLIANT if ACLs are configured for user access in Kubernetes Persistent Volumes.", - "Name": "Kubernetes Persistent Volumes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes Persistent Volumes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.25", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources in a namespace for principals from other Kubernetes namespaces. For example, the rule checks that the Role or ClusterRole does not allow any permissions related to 'pod'. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes Roles and RoleBindings", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes Roles and RoleBindings" + "Service": "RBAC" } ] }, { "Id": "7.2.1.26", "Description": "Checks that the access granted by the Kubernetes pod is restricted by any of the Kubernetes principals, service accounts, network policies, or namespaces that you provide. The rule is COMPLIANT if a network policy is not present.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.27", "Description": "Verifies that Kubernetes PersistentVolumeClaim permissions do not allow inter-namespace access beyond the specified controls in the PersistentVolume definition.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.1.28", "Description": "Checks if the Pod Security Policy in a Kubernetes cluster allows privileged operations. The rule is NON_COMPLIANT if privileged operations are permitted for any pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.1.29", "Description": "Checks if the Security Incident Response (SIR) team can access your Kubernetes cluster. The rule is NON_COMPLIANT if Kubernetes security measures are enabled but the role for SIR access is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.1", "Description": "Checks if a Kubernetes cluster is part of a specific organization (e.g., using labels or annotations). The rule is NON_COMPLIANT if a Kubernetes cluster does not have the required organization label or if the organization label value does not match the expected organization ID.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.2", "Description": "Checks if a Kubernetes PersistentVolumeClaim (PVC) has an associated ResourceQuota that prevents deletion or modification of related PersistentVolumes (PVs). The rule is NON_COMPLIANT if the PVC does not have an associated ResourceQuota or has quotas without proper limits on 'delete' and 'update' operations related to the storage resources.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.3", "Description": "Checks if a Kubernetes Pod has privileged security context enabled. The rule is NON_COMPLIANT for a Pod if 'privileged' is set to 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.4", "Description": "Checks if custom Kubernetes CustomResourceDefinitions (CRDs) have an associated RBAC policy. The rule is NON_COMPLIANT for CRDs without an associated RBAC policy attached.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.5", "Description": "Checks if a Kubernetes Pod has a ServiceAccount associated with it. The rule is NON_COMPLIANT if no ServiceAccount is attached to the Pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.2.6", "Description": "Checks if the securityContext in Pod definitions has privileged set to 'true'. The rule is NON_COMPLIANT if privileged is 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.7", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the securityContext of the Pod specification is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.8", "Description": "Checks if Kubernetes Pods specify a user for containers to run with. The rule is NON_COMPLIANT if the 'runAsUser' field is not present or set to '0' (root).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.9", "Description": "Checks if the Kubernetes Role or ClusterRole permissions do not allow actions that are denied by network policies. The rule is NON_COMPLIANT if any blocked action is allowed by the Kubernetes Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.2.2.10", "Description": "Checks if the RoleBindings and ClusterRoleBindings in Kubernetes do not allow unauthorized actions on all Secrets. The rule is NON_COMPLIANT if any unauthorized action is allowed on all Secrets by any RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.11", "Description": "Checks if the RBAC (Role-Based Access Control) feature is properly configured. The rule is NON_COMPLIANT if a Kubernetes ServiceAccount has any RoleBindings that associate it with inline roles, as the best practice is to use ClusterRoles or pre-defined roles instead.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.2.2.12", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a RoleBinding or ClusterRoleBinding containing a specific Role or ClusterRole is attached to the resource. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is attached to the resource.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, @@ -15249,314 +14389,314 @@ { "Id": "7.2.2.14", "Description": "Checks if Kubernetes Role or ClusterRole policies that you create have rules that grant permissions to all verbs on all resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole definition includes 'verbs': ['*'] over 'resources': ['*'].", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.15", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole allows full access to at least 1 Kubernetes resource or group of resources.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.2.2.16", "Description": "Checks if all specified Kubernetes RoleBindings are applied to the given Service Account. The rule is NON_COMPLIANT if a RoleBinding is missing for the Service Account.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "API Server" } ] }, { "Id": "7.2.2.17", "Description": "Checks if the Kubernetes root user (superuser) access is enabled. The rule is COMPLIANT if the root user has no access permissions (no tokens or credentials exist for the root user). Otherwise, NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.18", "Description": "Checks whether Kubernetes users are members of at least one RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.19", "Description": "Checks if none of your Kubernetes users or service accounts have direct role bindings. Users and service accounts should inherit permissions from roles or cluster roles through role bindings. The rule is NON_COMPLIANT if there is at least one role binding directly attached to the user or service account.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.20", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.2.21", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not configured for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.2.22", "Description": "Checks if a Kubernetes cluster's database (e.g., PostgreSQL, MySQL) has Role-based Access Control (RBAC) enabled for authentication. The rule is NON_COMPLIANT if the database does not have RBAC authentication enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.2.23", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.2.24", "Description": "Checks if Kubernetes Persistent Volumes allow user permissions through access control lists (ACLs). The rule is NON_COMPLIANT if ACLs are configured for user access in Kubernetes Persistent Volumes.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.25", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources for users from other namespaces or clusters. For example, the rule checks that the Role or ClusterRole does not allow any 'get', 'delete' actions on Pod resources. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.26", "Description": "Checks that the access granted by the Kubernetes service is restricted to specified namespaces, service accounts, or network policies that you provide. The rule is COMPLIANT if a NetworkPolicy is not present.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.27", "Description": "Checks if your Kubernetes PersistentVolumeClaims (PVC) permissions do not allow other inter-namespace access except for the control namespace policy that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.2.28", "Description": "Checks if the Kubernetes Pod Security Policy (PSP) allows privileged access for Pods. The rule is NON_COMPLIANT if a Pod is allowed to run with elevated privileges.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.2.29", "Description": "Checks if the Kubernetes Security Response Team (KSRT) can access your Kubernetes cluster. The rule is NON_COMPLIANT if the Role-Based Access Control (RBAC) is enabled but the role for KSRT access is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.2: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.3.1", "Description": "Checks if a Kubernetes Pod has privileged mode enabled. The rule is NON_COMPLIANT for a Pod if 'privileged' is set to 'true' in the security context.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.3.2", "Description": "Checks if custom Kubernetes Custom Resource Definitions (CRDs) have an admission policy attached. The rule is NON_COMPLIANT for CRDs without an admission policy attached.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.3.3", "Description": "Checks if the security context in the pod definition of a Kubernetes Deployment has 'privileged' set to 'true'. The rule is NON_COMPLIANT if 'privileged' is 'true'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.3.4", "Description": "Checks if Kubernetes Pods specify a user for containers to run as. The rule is NON_COMPLIANT if the 'securityContext.runAsUser' parameter is not present or set to '0'.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.3.5", "Description": "Checks if the Kubernetes Role or ClusterRole policies that you create do not allow ineligible actions on Kubernetes Secrets. The rule is NON_COMPLIANT if any ineligible action is allowed on Kubernetes Secrets by the managed Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.3.6", "Description": "Checks if the Role-based Access Control (RBAC) policies attached to your Kubernetes users, roles, and role bindings do not allow blocked actions on all specified Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on any Kubernetes resource in a role binding.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.2.3.7", "Description": "Checks if Kubernetes Role or ClusterRole policies allow unrestricted access by having rules that permit all verbs on all resources. The rule is NON_COMPLIANT if any user-defined Role or ClusterRole includes rules with 'verbs': ['*'] over all 'resources': ['*'].", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_wildcard_use_roles" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, @@ -15575,196 +14715,196 @@ { "Id": "7.2.3.9", "Description": "Checks if the Kubernetes Pod Security Policy allows privileged access for containers. The rule is NON_COMPLIANT if a Pod is running with elevated privileges.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_privileged_containers" ], "Attributes": [ { "Section": "7.2.3: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.4.1", "Description": "Checks whether Kubernetes Roles or RoleBindings have at least one associated ServiceAccount.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.2.4: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.2.4.2", "Description": "Checks if your Kubernetes Service Accounts have tokens that have not been used within the specified number of days you provided. The rule is NON_COMPLIANT if there are inactive accounts that have not recently used their tokens.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.4: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.4.3", "Description": "Checks if Kubernetes Secrets have been accessed within a specified number of days. The rule is NON_COMPLIANT if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.2.4: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.2.5.1.1", "Description": "Checks whether IAM groups have at least one Kubernetes user (Service Account).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.1.2", "Description": "Checks if your Kubernetes users (ServiceAccounts) have tokens that have not been used within the specified number of days you provided. The rule is NON_COMPLIANT if there are ServiceAccounts that have inactive tokens not recently used.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.1.3", "Description": "Checks if Kubernetes Secrets have been accessed within a specified number of days. The rule is NON_COMPLIANT if a Secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5.1: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.1", "Description": "Checks if a Kubernetes cluster is part of a specific organization. The rule is NON_COMPLIANT if a Kubernetes cluster is not part of the desired organization or the specified organization ID does not match the rule parameter OrganizationId.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.2", "Description": "Checks if a Kubernetes namespace has an associated network policy that restricts ingress and egress traffic, preventing unauthorized access. The rule is NON_COMPLIANT if the namespace does not have network policies or has policies without appropriate rules that deny specific traffic (e.g., HTTP, HTTPS) to sensitive services.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.3", "Description": "Checks if a Kubernetes pod has a ServiceAccount associated with it. The rule is NON_COMPLIANT if no ServiceAccount is attached to the pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.5.4", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the Pod Security Context is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.5", "Description": "Checks if the Kubernetes Role-based Access Control (RBAC) policies that you create do not allow access to Kubernetes Secrets that are restricted. The rule is NON_COMPLIANT if any restricted access is allowed to Kubernetes Secrets by the RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.2.5.6", "Description": "Checks if the Role-Based Access Control (RBAC) policies attached to your Kubernetes service accounts and roles do not allow prohibited actions on all Kubernetes resources. The rule is NON_COMPLIANT if any prohibited action is allowed on all Kubernetes resources in an RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.2.5.7", "Description": "Ensure that no Kubernetes ServiceAccounts have any associated inline policies, as inline policies can introduce security vulnerabilities. This rule is NON_COMPLIANT if a ServiceAccount has any role bindings that grant specific permissions directly to that account.", - "Name": "Kubernetes ServiceAccounts", + "Name": "CONTROLLERMANAGER", "Checks": [ "controllermanager_service_account_credentials" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes ServiceAccounts" + "Service": "CONTROLLERMANAGER" } ] }, { "Id": "7.2.5.8", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a RoleBinding or ClusterRoleBinding with the specified Role or ClusterRole is associated with the resource. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is linked to the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, @@ -15783,946 +14923,946 @@ { "Id": "7.2.5.10", "Description": "Checks if Kubernetes Role or ClusterRole configurations that you create have rules that grant permissions to all verbs on all resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole includes rules with 'verbs': ['*'] over 'resources': ['*'].", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.11", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom RBAC Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.2.5.12", "Description": "Checks if all specified Kubernetes RoleBindings are correctly linked to the associated Kubernetes Role. The rule is NON_COMPLIANT if a RoleBinding does not reference the correct Role.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.13", "Description": "Checks if none of your Kubernetes Service Accounts have direct RoleBindings or ClusterRoleBindings attached. Service Accounts must inherit permissions from Roles or ClusterRoles, and the rule is NON_COMPLIANT if there is at least one RoleBinding or ClusterRoleBinding attached to the Service Account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.5.14", "Description": "Checks if a Kubernetes Pod has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes Pod does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.5.16", "Description": "Checks if a Kubernetes database deployment (like PostgreSQL or MySQL) has Role-Based Access Control (RBAC) authentication enabled. The rule is NON_COMPLIANT if the database deployment does not have RBAC authentication enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.5.17", "Description": "Checks if a Kubernetes Cluster has Role-based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes Cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.2.5.18", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) allow user permissions through access control lists (RBAC). The rule is NON_COMPLIANT if RBAC is configured to allow unauthorized user access to Persistent Volume Claims.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions related to resource actions on namespaces for subjects from other namespaces. For example, the rule checks that the Role or ClusterRole does not allow subjects from other namespaces to perform any actions like get, list, or delete on specific resources. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.5.20", "Description": "Checks that the access granted by the Kubernetes ClusterRoleBinding is restricted by any of the Kubernetes principals, service accounts, namespaces, or IPs that you provide. The rule is COMPLIANT if a ClusterRoleBinding policy is not present.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.21", "Description": "Verifies that the Kubernetes Secrets do not allow unauthorized access to other namespaces and ensure that the permissions are controlled by the specified Role-Based Access Control (RBAC) policies.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.5.22", "Description": "Checks if the Incident Response Team can access your Kubernetes cluster. The rule is NON_COMPLIANT if the required role for the Incident Response Team is not configured, even though security features are enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.5: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.6.1", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the pod's securityContext is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.2.6: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.6.2", "Description": "Verifies if Kubernetes users are part of at least one RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.2.6: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.2.6.3", "Description": "Checks if Kubernetes ClusterRoleBinding has appropriate permissions for access control. The rule is NON_COMPLIANT if ClusterRoleBinding does not restrict access to sensitive resources.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.2.6: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.6.4", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions for principals from other namespaces or clusters, such as certain actions on Pods, Services, or ConfigMaps. For example, the rule checks that the Role or ClusterRole does not allow any 'get', 'delete' actions on Pods by users from different namespaces. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.2.6: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.2.6.5", "Description": "Checks if your Kubernetes Persistent Volume claims do not allow access from other namespaces besides the control namespace that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.2.6: Access to system components and data is appropriately defined and assigned.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.1", "Description": "Checks if a Kubernetes cluster is part of a defined namespace. The rule is NON_COMPLIANT if a Kubernetes pod is not part of the specified namespace or if the namespace does not match the rule parameter Namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.1.2", "Description": "Checks if a Kubernetes PersistentVolume has an attached role-based access control (RBAC) policy that prevents deletion of PersistentVolumeClaims. The rule is NON_COMPLIANT if the PersistentVolume does not have specific RBAC policies or has policies that do not include a suitable 'Deny' rule (with permissions such as delete on PersistentVolumeClaim).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.3", "Description": "Checks if a Kubernetes Pod has a Service Account attached to it. The rule is NON_COMPLIANT if no Service Account is associated with the Pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.4", "Description": "Checks if Kubernetes containers only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the pod specification is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.1.5", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow blocked actions on Kubernetes Secrets. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes Secrets by the managed RBAC policy.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.6", "Description": "Checks if the RBAC roles or ClusterRoles attached to your Kubernetes users do not allow unauthorized actions on all Kubernetes resources. The rule is NON_COMPLIANT if any unauthorized action is allowed on all Kubernetes resources in a Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.7", "Description": "Checks if the usage of PodSecurityPolicies is not in place. The rule is NON_COMPLIANT if a Kubernetes user or service account has any PodSecurityPolicy defined inline.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.8", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a role binding to the specified Role or ClusterRole is present for the input user or service account. The rule is NON_COMPLIANT if the role binding exists linking the user or service account to the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.9", "Description": "Checks whether the Kubernetes Role or ClusterRole is bound to a ServiceAccount, a User, or a Group, and if it grants necessary permissions to access specific resources.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.3.1.10", "Description": "Checks if Kubernetes Role or ClusterRole resources grant permissions to all verbs on all resources. The rule is NON_COMPLIANT if any customer-managed Role or ClusterRole includes rules with verbs set to '*' and resources set to '*'.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.11", "Description": "Checks if Kubernetes Role or ClusterRole permissions that you create grant access to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.12", "Description": "Checks if all required Kubernetes RoleBindings or ClusterRoleBindings are associated with the specified Kubernetes ServiceAccount. The rule is NON_COMPLIANT if any required binding is not associated with the ServiceAccount.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.3.1.13", "Description": "Checks if none of your Kubernetes Service Accounts have roles or role bindings directly attached. Service Accounts must inherit permissions from ClusterRoles or RoleBindings. The rule is NON_COMPLIANT if there is at least one Role or RoleBinding directly attached to the Service Account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.14", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC features are not configured for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.16", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled for managing permissions. The rule is NON_COMPLIANT if RBAC is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.17", "Description": "Checks if a Kubernetes database pod has role-based access control (RBAC) authentication enabled. The rule is NON_COMPLIANT if the Kubernetes database pod does not have RBAC authentication enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.1.18", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) allow user permissions through access control lists (ACLs). The rule is NON_COMPLIANT if ACLs are configured for user access in Kubernetes Persistent Volume Claims.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources within a namespace or cluster for subjects from other namespaces or clusters. For example, the rule checks that the Role or ClusterRole does not allow another namespace to perform any get, delete, or list actions on any resource within the namespace. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.3.1.20", "Description": "Verifies that the access control policies for a Kubernetes cluster's resources are correctly configured to restrict access based on specific Kubernetes users, service accounts, or roles. The rule is COMPLIANT if there are no RoleBindings or ClusterRoleBindings present that grant access.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.21", "Description": "Checks if your Kubernetes PersistentVolumeClaim policies do not allow inter-namespace permissions other than the control PersistentVolumeClaim policy that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.1.22", "Description": "Checks if the Kubernetes Security Response Team (KST) can access your Kubernetes cluster. The rule is NON_COMPLIANT if Kubernetes Network Policy is enabled but the role for KST access is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.1: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.1", "Description": "Checks if a Kubernetes namespace is part of a specific label set. The rule is NON_COMPLIANT if the namespace does not have the expected label or if the master namespace label does not match the specified MasterLabel.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.2", "Description": "Checks if a KubernetesNamespace has an attached Role or ClusterRole that includes a policy preventing the deletion of specific resources. The rule is NON_COMPLIANT if the KubernetesNamespace does not have roles or role bindings that include a suitable 'deny' permission (e.g., delete actions on resources such as Pods, PersistentVolumeClaims, etc.).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.3", "Description": "Checks if a Kubernetes Pod has a RoleBinding or ClusterRoleBinding attached to it. The rule is NON_COMPLIANT if no RoleBinding or ClusterRoleBinding is attached to the Pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.4", "Description": "Checks if Kubernetes containers only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the securityContext.readOnlyRootFilesystem parameter in the Pod specification is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.5", "Description": "Checks if the Kubernetes Role or ClusterRole you create does not allow blocked actions on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes resources by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.6", "Description": "Checks if the Role-Based Access Control (RBAC) policies attached to your Kubernetes users, roles, and clusters do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in an RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.3.2.7", "Description": "Checks if the use of inline policy equivalent in Kubernetes, which would be RoleBindings and ClusterRoleBindings, is not in use. The rule is NON_COMPLIANT if a Kubernetes ServiceAccount, Role, or ClusterRole has any RoleBindings with inline policies.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "Role-Based Access Control (RBAC)", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "Role-Based Access Control (RBAC)" } ] }, { "Id": "7.3.2.8", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a RoleBinding or ClusterRoleBinding that references a specific Role or ClusterRole is attached to the resource. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding that references the Role or ClusterRole is found.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.2.9", "Description": "Checks whether the Role ARN is associated with a Service Account, or a Role Binding that includes one or more Users/Groups, or a Cluster Role Binding with one or more Service Accounts.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.3.2.10", "Description": "Checks if Kubernetes Role and ClusterRole definitions have rules that allow permissions to all verbs on all resources. The rule is NON_COMPLIANT if any Role or ClusterRole includes a rule with verbs set to '*' and resources set to '*'.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.2.11", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom role allows full access to at least 1 Kubernetes resource type.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.3.2.12", "Description": "Checks if all specified ConfigMaps are attached to the Kubernetes Deployment. The rule is NON_COMPLIANT if a ConfigMap is not attached to the Deployment.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.2.13", "Description": "Checks if none of your Kubernetes Service Accounts have roles or role bindings directly attached. Service Accounts must inherit permissions from Cluster Roles or Role Bindings. The status is NON_COMPLIANT if there is at least one Role or Role Binding that is attached directly to the Service Account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.2.14", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.2.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.2.16", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if Kubernetes RBAC is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.2.17", "Description": "Checks if a Kubernetes Pod has RBAC (Role-Based Access Control) enabled for its ServiceAccount. The rule is NON_COMPLIANT if the Pod's ServiceAccount does not have RBAC enabled.", - "Name": "Kubernetes Pod", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes Pod" + "Service": "RBAC" } ] }, { "Id": "7.3.2.18", "Description": "Checks if Kubernetes PersistentVolumeClaims (PVCs) allow user permissions through Role-Based Access Control (RBAC) settings. The rule is NON_COMPLIANT if RBAC is configured to allow unauthorized user access to PVCs.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.2.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted verbs (like get, delete) on resources for principals from other namespaces or external users. For example, the rule checks that a Role or ClusterRole does not allow a user to perform any verbs like get or delete on any resource in a namespace. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.3.2.20", "Description": "Ensures that Kubernetes access control policies treat permissions as restricted, validating that no access is granted to the Kubernetes resources by any unauthorized users, service accounts, or IP ranges that are not explicitly defined. The rule is COMPLIANT if a Role or ClusterRole with no permissions is not present.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.3.2.21", "Description": "Checks if your Kubernetes Persistent Volume Claims (PVC) policies do not allow other inter-namespace permissions than the control Persistent Volume (PV) policy that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.2.22", "Description": "Checks if the Kubernetes Security Team (KST) can access your Kubernetes cluster. The rule is NON_COMPLIANT if network policies are enabled but the role for KST access is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.2: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.3.1", "Description": "Checks if a Kubernetes cluster is part of a specified namespace. The rule is NON_COMPLIANT if a pod is not running in the designated namespace or if the namespace does not match the specified parameter Namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.3.2", "Description": "Checks if a Kubernetes namespace has an associated RoleBindings or ClusterRoleBindings that prevent deletion of PersistentVolumeClaims (PVCs). The rule is NON_COMPLIANT if the namespace does not have RoleBindings/ClusterRoleBindings or those bindings do not include a suitable 'Deny' statement (statements that restrict the delete actions on PersistentVolumeClaims).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.3.3", "Description": "Checks if a Kubernetes Pod has a Service Account attached to it. The rule is NON_COMPLIANT if no Service Account is attached to the Pod.", - "Name": "Kubernetes Pod", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes Pod" + "Service": "API Server" } ] }, { "Id": "7.3.3.4", "Description": "Checks if Kubernetes Pods have read-only file system access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the Pod's securityContext is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.3.5", "Description": "Checks if the Kubernetes Role or ClusterRole policies that you create do not allow blocked actions on Kubernetes Secrets. The rule is NON_COMPLIANT if any blocked action is allowed on Kubernetes Secrets by the managed Role or ClusterRole policies.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.3.6", "Description": "Checks if the RBAC (Role-Based Access Control) policies attached to your Kubernetes users, service accounts, and roles do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is permitted on all Kubernetes resources in an RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "7.3.3.7", "Description": "Checks if the Kubernetes Roles or ClusterRoles feature is not in use as inline policies. The rule is NON_COMPLIANT if a Kubernetes user or service account has any Roles or ClusterRoles defined inline that grant permissions directly without using a predefined RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.3.8", "Description": "Checks in each Kubernetes Role or ClusterRole, if a specific RoleBinding or ClusterRoleBinding that grants permissions is associated with the Role or ClusterRole. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is linked to the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, @@ -16741,306 +15881,294 @@ { "Id": "7.3.3.10", "Description": "Checks if Kubernetes Role or ClusterRole definitions include permissions that grant access to all actions on all resources. The rule is NON_COMPLIANT if any Role or ClusterRole includes rules with 'verbs': ['*'] for 'apiGroups': ['*'] and 'resources': ['*'].", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.3.11", "Description": "Checks if Kubernetes Role or ClusterRole policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes Role-based Access Control (RBAC)", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes Role-based Access Control (RBAC)" + "Service": "RBAC" } ] }, { "Id": "7.3.3.12", "Description": "Checks if all specified Kubernetes Roles or ClusterRoles are granted to the ServiceAccount. The rule is NON_COMPLIANT if a Role or ClusterRole is not bound to the ServiceAccount.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.13", "Description": "Checks if none of your Kubernetes Service Accounts have policies (RoleBindings or ClusterRoleBindings) attached directly. Service Accounts must inherit permissions from Roles or ClusterRoles. The rule is NON_COMPLIANT if there is at least one RoleBinding or ClusterRoleBinding that is directly attached to the Service Account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.14", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not configured for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.16", "Description": "Checks if a Kubernetes deployment has Role-Based Access Control (RBAC) enabled for authentication. The rule is NON_COMPLIANT if the Kubernetes deployment does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.17", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "7.3.3.18", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) allow user permissions through access control settings in their underlying storage classes. The rule is NON_COMPLIANT if access control lists (ACLs) are configured for user access in Persistent Volume Claims.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "7.3.3.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources within the namespace for subjects from other Kubernetes namespaces. For example, the rule checks that the Role or ClusterRole does not allow any 'get' or 'delete' actions on specific resources (like Pods, Secrets, etc.) from other namespaces. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "7.3.3.20", "Description": "Checks that the access granted by the Kubernetes cluster is restricted by any of the Kubernetes subjects, such as users, service accounts, groups, or network policies that you provide. The rule is COMPLIANT if a Role or ClusterRole binding is not present.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "7.3.3.21", "Description": "Verifies that the Kubernetes cluster role bindings do not permit users from other namespaces to access the resources defined in the specified role, ensuring that only authorized roles have the necessary permissions.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "7.3.3.22", "Description": "Checks if the Security Response Team (SRT) can access your Kubernetes cluster. The rule is NON_COMPLIANT if the necessary permissions for SRT access are not configured in the RoleBindings for the Security context in Kubernetes.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "7.3.3: Access to system components and data is managed via an access control system(s).", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.1.1", "Description": "Checks if running Kubernetes pods are deployed using secrets for sensitive information. The rule is NON_COMPLIANT if a running pod is using hardcoded secrets in environment variables instead of Kubernetes Secrets.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.2.1: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.1.2", "Description": "Checks whether Kubernetes namespaces have at least one associated pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.1: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.1.3", "Description": "Checks whether the Role or ClusterRole is bound to a specific User, Group, or ServiceAccount in Kubernetes.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.1: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.1.4", "Description": "Checks if root user credentials are configured in Kubernetes. The rule is COMPLIANT if the root user credentials do not exist. Otherwise, NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.2.1: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.1.5", "Description": "Checks whether Kubernetes service accounts are members of at least one Kubernetes role or role binding.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.1: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" - } - ] - }, - { - "Id": "8.2.2.1", - "Description": "Checks if the Kubernetes Pod specification contains environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as plain text in the spec. The rule is NON_COMPLIANT when these environment variables are present in plaintext credentials within a Pod definition.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.2.2", "Description": "Checks if running Kubernetes pods are deployed using service accounts. The rule is NON_COMPLIANT if a running pod is deployed without an associated service account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.2.3", "Description": "Checks if Kubernetes Secrets are exposed as environment variables in a Pod definition. The rule is NON_COMPLIANT if one or more environment variable names correspond to keys in the 'secretKeys' list, while ignoring environment variables sourced from other systems like Amazon S3.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.2.4", "Description": "Verifies if Kubernetes RBAC (Role-Based Access Control) groups have at least one associated user or service account.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.2.2.5", "Description": "Checks whether a Kubernetes Role or ClusterRole is bound to a ServiceAccount, or to a User or Group of Users, enabling access to specific resources within a namespace or cluster.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, @@ -17059,74 +16187,74 @@ { "Id": "8.2.2.7", "Description": "Verifies if Kubernetes users or service accounts are associated with at least one RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.2.8", "Description": "Checks if Kubernetes Secrets have a defined lifecycle policy for automatic rotation. If a maximum rotation frequency is specified, it compares the current rotation schedule against this maximum allowed frequency. The rule is NON_COMPLIANT if the secret does not have a rotation strategy defined, or if the rotation frequency exceeds the specified maximum.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.2.9", "Description": "Checks if Kubernetes Secrets are updated successfully according to the defined rotation schedule. The system monitors the timestamp of the last update and flags the secret as NON_COMPLIANT if the scheduled rotation time passes without an update.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.2.10", "Description": "Checks if Kubernetes Secrets have been updated (rotated) in the past specified number of days. The rule is NON_COMPLIANT if a secret has not been updated for more than maxDaysSinceUpdate number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.2.11", "Description": "Checks if Kubernetes secrets have been accessed within a specified number of days. The rule is NON_COMPLIANT if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.2: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.4.1", "Description": "Checks if running Kubernetes pods are launched using service accounts. The rule is NON_COMPLIANT if a running pod is launched without a service account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.2.4: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -17145,24 +16273,24 @@ { "Id": "8.2.4.3", "Description": "Checks whether a Role in Kubernetes is attached to a User, a Group of Users, or a Service Account with one or more trusted entities.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.4: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.4.4", "Description": "Checks if the Kubernetes admin user access token is available. The rule is COMPLIANT if the user access token does not exist. Otherwise, NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.4: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -17181,404 +16309,404 @@ { "Id": "8.2.5.1", "Description": "Checks if running Kubernetes Pods are launched using secrets for sensitive information such as SSH keys. The rule is NON_COMPLIANT if a running Pod is launched with sensitive information directly in the specification instead of using Kubernetes secrets.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.2.5: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.5.2", "Description": "Verifies that at least one Kubernetes user is associated with each role or group in Kubernetes RBAC (Role-Based Access Control).", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.5: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.2.5.3", "Description": "Checks whether the Kubernetes Role or ClusterRole is bound to a ServiceAccount, or a group of users (via RoleBinding or ClusterRoleBinding) with one or more ServiceAccounts, or a PodSecurityPolicy with one or more trusted entities.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.5: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.5.4", "Description": "Checks if the Kubernetes root user (cluster-admin) has any access keys. The rule is COMPLIANT if no service accounts or users with cluster-admin privileges exist that possess access keys. Otherwise, NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.2.5: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.5.5", "Description": "Checks whether Kubernetes users are members of at least one RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.5: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.6.1", "Description": "Checks whether Kubernetes RBAC roles have at least one user or service account associated with them.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.6: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.2.6.2", "Description": "Checks if your Kubernetes service accounts have tokens that have not been used within the specified number of days you provided. The rule is NON_COMPLIANT if there are inactive service accounts not recently used.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.6: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.6.3", "Description": "Checks if Kubernetes Secrets have been accessed within a specified number of days. The rule is NON_COMPLIANT if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.6: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.1", "Description": "Checks if a Kubernetes namespace is associated with a specific organization. The rule is NON_COMPLIANT if a namespace is not part of the defined organization or the organization master namespace does not match the specified MasterNamespaceId.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.2", "Description": "Checks if a Kubernetes namespace has a resource-based policy (such as NetworkPolicy or PodSecurityPolicy) that prevents deletion of critical Pods. The rule is NON_COMPLIANT if the namespace does not have resource-based policies or has policies without a suitable 'Deny' statement (statements that include delete actions on Pods, Services, or related resources).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.3", "Description": "Checks if a Kubernetes pod has an associated Kubernetes Service Account. The rule is NON_COMPLIANT if no Service Account is attached to the pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.7.4", "Description": "Checks if Kubernetes containers have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the container specification of a Pod or Deployment is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.5", "Description": "Checks if the Kubernetes Role or ClusterRole policies that you create do not allow blocked actions on specific resources. The rule is NON_COMPLIANT if any blocked action is allowed on the specified resources by the Role or ClusterRole policies.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.6", "Description": "Checks if the role policies attached to your Kubernetes service accounts do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in a role policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.7", "Description": "Checks if the Role-based access control (RBAC) feature in Kubernetes is not in use. The rule is NON_COMPLIANT if any Kubernetes user or service account has any Role or ClusterRole associated with it directly.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.2.7.8", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a RoleBinding or ClusterRoleBinding in the input parameter is associated with the Role or ClusterRole resource. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is associated with the Role or ClusterRole resource.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.2.7.9", "Description": "Checks whether the Role ARN is attached to a Kubernetes ServiceAccount, or a Role/ClusterRole with one or more associated ServiceAccounts, or a Pod with a service account identity.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.10", "Description": "Checks if Kubernetes Role or ClusterRole policies grant permissions to all actions on all resources. The rule is NON_COMPLIANT if any customer managed Role or ClusterRole includes rules with 'verbs': ['*'] on the 'resources': ['*'].", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.2.7.11", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any Kubernetes Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.2.7.12", "Description": "Checks if all specified Kubernetes RoleBindings are attached to the ServiceAccount. The rule is NON_COMPLIANT if a RoleBinding is not attached to the ServiceAccount.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "Role-Based Access Control (RBAC)", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "Role-Based Access Control (RBAC)" } ] }, { "Id": "8.2.7.13", "Description": "Checks if none of your Kubernetes users have roles or role bindings directly attached. Kubernetes users must inherit permissions from groups or cluster roles. The rule is NON_COMPLIANT if there is at least one role or role binding that is attached directly to the Kubernetes user.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.14", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.7.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the RBAC is not configured for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.7.16", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled for authentication. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.7.17", "Description": "Checks if a Kubernetes Pod has role-based access control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes Pod does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.7.18", "Description": "Checks if Kubernetes Persistent Volumes (PVs) allow user permissions through access control policies. The rule is NON_COMPLIANT if access control policies are configured for user access in Kubernetes Persistent Volumes.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.7.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions for principals from other namespaces or external entities on resources within the namespace. For example, the rule checks that the Role or ClusterRole does not allow any actions like 'get', 'delete', or 'list' on resources when accessed by external users. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role or ClusterRole.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.2.7.20", "Description": "Checks that the access granted by the Kubernetes namespace is restricted by any of the Kubernetes roles, role bindings, service accounts, users, or network policies that you provide. The rule is COMPLIANT if a network policy is not present.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.7.21", "Description": "Checks if your Kubernetes PersistentVolumes policies do not allow other inter-account permissions than the control PersistentVolume policy that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.7.22", "Description": "Checks if the Kubernetes Security Team (KST) can access your Kubernetes cluster. The rule is NON_COMPLIANT if Kubernetes RBAC is enabled but the role for KST access is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.7: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.1", "Description": "Checks if a Kubernetes cluster is part of a specific namespace or if the namespace matches the defined MasterNamespaceId. The rule is NON_COMPLIANT if a Kubernetes cluster is not part of the specified namespace or if the namespace master ID does not match the rule parameter MasterNamespaceId.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -17597,106 +16725,106 @@ { "Id": "8.2.8.3", "Description": "Checks if a Kubernetes PersistentVolumeClaim (PVC) has annotations or policies that prevent deletion of associated PersistentVolume (PV) resources. The rule is NON_COMPLIANT if the PVC does not have deletion policies or has policies without suitable 'Deny' annotations (annotations that prevent 'delete' operations on the PV).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.4", "Description": "Checks if your Kubernetes Pod is configured with the Pod Security Standards requiring the use of the 'RunAsNonRoot' security context. The rule is NON_COMPLIANT if the security context does not enforce this setting.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.5", "Description": "Checks if a Kubernetes Pod has a ServiceAccount attached to it. The rule is NON_COMPLIANT if no ServiceAccount is attached to the Pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.6", "Description": "Checks if Kubernetes Pods have a read-only root filesystem by verifying that the 'readOnlyRootFilesystem' parameter in the container spec is set to 'true'. The rule is NON_COMPLIANT if this parameter is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.7", "Description": "Checks if the Kubernetes Role or ClusterRole created does not allow blocked actions on Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed by the Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.8", "Description": "Checks if the RoleBindings attached to your Kubernetes ServiceAccounts do not allow access to blocked resources in all Kubernetes namespaces. The rule is NON_COMPLIANT if any blocked resource access is allowed in a RoleBinding.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.8.9", "Description": "Checks if the Pod Security Policy (PSP) feature is not in use. The rule is NON_COMPLIANT if a Kubernetes Pod has any pod specifications that allow the use of inline security policies.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.10", "Description": "Checks in each Kubernetes Role or ClusterRole resource if a RoleBinding or ClusterRoleBinding with the specified role is attached to it. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is associated with the Role or ClusterRole.", - "Name": "Kubernetes RBAC (Role-Based Access Control)", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes RBAC (Role-Based Access Control)" + "Service": "RBAC" } ] }, @@ -17715,200 +16843,200 @@ { "Id": "8.2.8.12", "Description": "Checks if Kubernetes Role or ClusterRole objects grant permissions to all verbs on all resources. The rule is NON_COMPLIANT if any custom Role or ClusterRole has rules that include 'verbs': ['*'] over 'resources': ['*'].", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.8.13", "Description": "Checks if Kubernetes Role and ClusterRole bindings grant permissions that allow full access to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.8.14", "Description": "Checks if all required Kubernetes Roles or ClusterRoles specified in the list are bound to the service account in the Kubernetes cluster. The rule is NON_COMPLIANT if a required Role or ClusterRole is not bound to the service account.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "RBAC" } ] }, { "Id": "8.2.8.15", "Description": "Checks if none of your Kubernetes Service Accounts have default RoleBindings or ClusterRoleBindings attached. Service Accounts must inherit permissions from Roles or ClusterRoles. The rule is NON_COMPLIANT if there is at least one RoleBinding or ClusterRoleBinding that is directly attached to the Service Account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.16", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.17", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.18", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.19", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.2.8.20", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) allow user access through access policies. The rule is NON_COMPLIANT if user access policies are configured for PVCs.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.8.21", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources for users from other namespaces or service accounts. For example, the rule checks that the Role/ClusterRole does not allow any 'get', 'list', or 'delete' permissions on pods for accounts that are not in the specified namespace. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Role/ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.22", "Description": "Checks that the access granted by the Kubernetes Role or ClusterRole is restricted by any specific users, service accounts, or network policies that you provide. The rule is COMPLIANT if a Role/ClusterRole is not present.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.2.8.23", "Description": "Checks if your Kubernetes PersistentVolumeClaims (PVC) are not allowing other inter-namespace permissions other than the control PersistentVolume (PV) policies that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.2.8.24", "Description": "Verifies if the Shield Response Team (SRT) has the necessary permissions to access the Kubernetes cluster. The status is NON_COMPLIANT if the Kubernetes cluster has enabled the equivalent of Shield Advanced but the role for SRT access is not configured properly.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.2.8: User identification and related accounts for users and administrators are strictly managed throughout an accounts lifecycle.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.10.1.1", "Description": "Checks if Kubernetes secrets used for access tokens are rotated (changed) within the number of days specified in maxTokenAge. The rule is NON_COMPLIANT if access tokens are not rotated within the specified time period. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.10.1: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.10.1.2", "Description": "Checks if a Kubernetes Secret has a defined expiration time or automated rotation mechanism. The rule also checks an optional maxAllowedRotationFrequency parameter. If specified, the rotation frequency of the Secret is compared with this maximum allowed frequency. The rule is NON_COMPLIANT if the Secret does not have any rotation scheduled or if the frequency exceeds the specified maximum allowed value.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.10.1: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, @@ -17927,116 +17055,116 @@ { "Id": "8.3.10.1.4", "Description": "Checks if Kubernetes Secrets have been updated (rotated) in the past specified number of days. The rule is NON_COMPLIANT if a secret has not been updated for more than maxDaysSinceUpdate number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.10.1: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.11.1", "Description": "Checks if running Kubernetes Pods are launched using Secrets for sensitive data. The rule is NON_COMPLIANT if a running Pod is launched with sensitive data hardcoded in the Pod specifications instead of being stored in Kubernetes Secrets.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.11: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.11.2", "Description": "Checks whether Kubernetes groups have at least one user associated with them.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.11: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.11.3", "Description": "Checks whether the Role ARN is attached to a Kubernetes ServiceAccount, or a RoleBinding with one or more ServiceAccounts, or a ClusterRole with one or more trusted entities.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.11: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.11.4", "Description": "Checks if the Kubernetes cluster has a Role or ClusterRoleBinding that grants 'root' access. The rule is COMPLIANT if no such Role or ClusterRoleBinding exists. Otherwise, NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.3.11: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.11.5", "Description": "Verifies if Kubernetes users have access to at least one RoleBinding or ClusterRoleBinding.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.3.11: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.3.2.1", "Description": "Checks if all HTTP services in Kubernetes are configured to redirect HTTP traffic to HTTPS. The rule is NON_COMPLIANT if one or more HTTP services do not have HTTP to HTTPS redirection configured or if any HTTP service forwards traffic to another HTTP service instead of redirecting.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.2", "Description": "Checks if all HTTP methods in the Kubernetes Ingress resources have caching enabled and caching is encrypted. The rule is NON_COMPLIANT if any method in a Kubernetes Ingress does not have caching enabled or the caching is not encrypted.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.3", "Description": "Checks if a Kubernetes Secret is encrypted at rest. The rule is NON_COMPLIANT if encryption of Secrets at rest is not enabled in the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, @@ -18055,124 +17183,112 @@ { "Id": "8.3.2.5", "Description": "Checks if Kubernetes Ingress resources are configured to use deprecated SSL protocols for HTTPS communication between Ingress controllers and backend services. This rule is NON_COMPLIANT for an Ingress resource if any 'tls' configuration includes 'SSLv3'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.6", "Description": "Checks if Kubernetes Ingress resources are enforcing HTTPS for backend services. The rule is NON_COMPLIANT if 'backend.service.port' is configured with a non-secure port (e.g., 80) or if 'ingress.spec.tls' is not specified while using 'path' with a non-secure backend service.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.7", "Description": "Checks if your Kubernetes Ingress resources enforce HTTPS for traffic. The rule is NON_COMPLIANT if the value of the 'nginx.ingress.kubernetes.io/force-ssl-redirect' annotation is set to 'false'.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.8", "Description": "Checks if Kubernetes Logging (e.g., Fluentd) is configured to encrypt logs at rest using a specified encryption key or mechanism. The rule is NON_COMPLIANT if logging is not encrypted or is using an encryption method not specified in the rule parameter.", - "Name": "Kubernetes Logging", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Logging" + "Service": "API Server" } ] }, { "Id": "8.3.2.9", "Description": "Checks if Kubernetes Secrets are configured to use encryption at rest. The rule is COMPLIANT if the encryption provider is defined in the kube-apiserver configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.2.10", "Description": "Checks if a Kubernetes pod specification has encryption enabled for all of its secrets. The rule is NON_COMPLIANT if 'encryptionEnabled' is set to 'false' for any of the secret configurations used within the pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "8.3.2.11", - "Description": "Checks if the Kubernetes namespace contains environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in any pod. The rule is NON_COMPLIANT when any pod in the namespace has plaintext credentials in environment variables.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.12", "Description": "Checks if a Kubernetes Pod configured with Persistent Volumes has encryption enabled for its storage. The rule is NON_COMPLIANT if 'encryptionDisabled' is set to 'true' in the PersistentVolumeClaim specifications.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.13", "Description": "Checks if Kubernetes etcd clusters are encrypted. The rule is NON_COMPLIANT if an etcd cluster is not encrypted.", - "Name": "etcd", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "etcd" + "Service": "ETCD" } ] }, { "Id": "8.3.2.14", "Description": "Checks if your Kubernetes Service has the 'spec.type' set to 'LoadBalancer'. The rule is NON_COMPLIANT if a Service does not use LoadBalancer type, which is necessary for exposing the service securely over the network.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, @@ -18191,76 +17307,76 @@ { "Id": "8.3.2.16", "Description": "Checks if Kubernetes Secrets used for Redis data stores are configured to require TLS/SSL encryption for data in transit between Redis instances and clients. The rule is NON_COMPLIANT if TLS/SSL encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.17", "Description": "Checks if storage encryption is enabled for your Kubernetes persistent volumes. The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.18", "Description": "Checks if a Kubernetes PersistentVolume is encrypted. The rule is NON_COMPLIANT if the PersistentVolume is not encrypted, or if the specified encryption key is not present in the encryption key parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.19", "Description": "Checks if the Kubernetes Secrets are encrypted at rest and checks their status. The rule is COMPLIANT if encryption is enabled or enabling.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.20", "Description": "Checks if Kubernetes Persistent Volumes (PV) have encryption enabled by default. The rule is NON_COMPLIANT if encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.21", "Description": "Checks if Kubernetes secrets are passed as container environment variables. The rule is NON_COMPLIANT if 1 or more environment variable keys match a key listed in the 'secretKeys' parameter (excluding environment variables from other locations such as ConfigMaps or Persistent Volumes).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -18279,66 +17395,42 @@ { "Id": "8.3.2.23", "Description": "Checks if Kubernetes clusters are configured to have secrets encrypted using a specified encryption provider. The rule is NON_COMPLIANT if a Kubernetes cluster does not have an encryption configuration defined or if the encryption configuration does not include secrets as a resource.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "8.3.2.24", - "Description": "Checks if Kubernetes clusters on Amazon Elastic Kubernetes Service have secrets encrypted using AWS Key Management Service (KMS) keys.", - "Name": "Amazon Elastic Kubernetes Service (EKS)", - "Checks": [], - "Attributes": [ - { - "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Amazon Elastic Kubernetes Service (EKS)" + "Service": "API Server" } ] }, { "Id": "8.3.2.25", "Description": "Checks if Kubernetes secrets have encryption enabled at rest. The rule is NON_COMPLIANT for a Kubernetes secret if 'encryptionProvider' is disabled or if the KMS key ARN does not match the defined KMS configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "8.3.2.26", - "Description": "Checks if Kubernetes StatefulSets have encryption-in-transit enabled. The rule is NON_COMPLIANT for a StatefulSet if the TLS encryption for communication between pods is not configured.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.2.27", "Description": "Checks if Kubernetes clusters have encryption at rest configuration enabled in etcd. The rule is NON_COMPLIANT if the encryption at rest configuration for etcd is not enabled.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, @@ -18357,142 +17449,142 @@ { "Id": "8.3.2.29", "Description": "Checks if Kubernetes Ingress resources are configured to use TLS certificates provided by a certificate manager. To use this rule, ensure that the Ingress resource has TLS settings defined. This rule only applies to Ingress resources and does not apply to other service types like NodePort or LoadBalancer services.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.30", "Description": "Checks whether your Kubernetes Ingress resources are using a custom TLS secret for SSL termination. The rule is only applicable if there are Ingress resources configured with SSL/TLS termination.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "8.3.2.31", "Description": "Checks if the Kubernetes Ingress controller is using a predefined TLS configuration. The rule is NON_COMPLIANT if the Ingress resource's TLS configuration does not match the specified 'predefinedPolicyName'.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "8.3.2.32", "Description": "Checks if the Kubernetes Service is configured with HTTPS or TLS for secure communication. The rule is NON_COMPLIANT if a service is not configured with TLS or HTTPS.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "8.3.2.33", "Description": "Checks if Kubernetes clusters have RBAC (Role-Based Access Control) configured. The rule is NON_COMPLIANT if the cluster does not have RBAC enabled or if the configured roles do not satisfy the specified access control parameters.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.2.34", "Description": "Checks if attached Kubernetes Persistent Volumes (PVs) are encrypted and optionally are encrypted with a specified KMS key. The rule is NON_COMPLIANT if attached PVs are unencrypted or are encrypted with a KMS key not in the supplied parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.35", "Description": "Checks if Kubernetes secrets used in a Kinesis-like streaming application are encrypted at rest. The rule is NON_COMPLIANT for a Kubernetes secret if 'encryption' is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.36", "Description": "Checks if a Kubernetes cluster's communication between pods is encrypted using TLS. The rule is NON_COMPLIANT if plain text communication is enabled for network traffic between pod-to-pod connections.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.37", "Description": "Checks if storage encryption is enabled for your Kubernetes Persistent Volumes. The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.38", "Description": "Checks if a Kubernetes cluster has Persistent Volume Claims (PVCs) that are encrypted. The rule is NON_COMPLIANT if any PVC in the cluster does not have encryption enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.39", "Description": "Checks if Kubernetes clusters have encryption at rest enabled for etcd. The rule is NON_COMPLIANT if the etcd encryption is not configured properly.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, @@ -18511,516 +17603,516 @@ { "Id": "8.3.2.41", "Description": "Check if Kubernetes Cluster nodes are encrypted end to end. The rule is NON_COMPLIANT if the etcd encryption is not enabled on the cluster.", - "Name": "Kubernetes", + "Name": "ETCD", "Checks": [ "etcd_tls_encryption" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "ETCD" } ] }, { "Id": "8.3.2.42", "Description": "Checks if a Kubernetes Persistent Volume (PV) is encrypted at rest. The rule is NON_COMPLIANT if a Persistent Volume is not encrypted at rest.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.43", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) are using encrypted Persistent Volumes (PVs). The rule is NON_COMPLIANT if the Persistent Volumes are not encrypted.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.44", "Description": "Checks if storage encryption is enabled for your Kubernetes Persistent Volume Claims (PVCs). The rule is NON_COMPLIANT if storage encryption is not enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.45", "Description": "Checks if Kubernetes clusters have the specified security settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not encrypted or encrypted with another key, or if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.46", "Description": "Checks if Kubernetes clusters are using a specified encryption provider for secrets. The rule is COMPLIANT if encryption is enabled and the cluster is using the specified encryption provider key. The rule is NON_COMPLIANT if the cluster is not using encryption or using a different key.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.2.47", "Description": "Checks if Kubernetes clusters require TLS/SSL encryption for API server connections. The rule is NON_COMPLIANT if the API server's TLS configuration is not enabled or improperly configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.2.48", "Description": "Checks if your Kubernetes persistent volume (PV) is bound to a persistent volume claim (PVC) that ensures encryption at rest is enabled or if there are specific policies that deny access to unencrypted volumes. The rule is NON_COMPLIANT if your persistent volume does not have encryption enabled by default.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.49", "Description": "Checks if Kubernetes services have network policies that enforce TLS for communication. The rule is NON_COMPLIANT if any service allows unencrypted HTTP traffic.", - "Name": "Kubernetes Services", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Services" + "Service": "API Server" } ] }, { "Id": "8.3.2.50", "Description": "Checks if the persistent volumes (PVs) in Kubernetes are encrypted using a specific encryption provider. The rule is NON_COMPLIANT if the persistent volume is not encrypted.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.2.51", "Description": "Checks if Kubernetes Secrets are used to store sensitive information for a specific deployment. The rule is NON_COMPLIANT if a Secret for storing sensitive data (e.g., passwords, API keys) is not specified in the deployment configuration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.52", "Description": "Checks if a Kubernetes secret is configured for a pod. The rule is NON_COMPLIANT if 'imagePullSecrets' is not specified for the pod.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.53", "Description": "Checks if all Kubernetes secrets are encrypted using an encryption provider for Kubernetes, either a customer-managed key or the default key provided by Kubernetes. The rule is COMPLIANT if a secret is encrypted using a customer-managed key. This rule is NON_COMPLIANT if a secret is encrypted using the default key.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.2.54", "Description": "Checks if Kubernetes Secrets are encrypted in transit and at rest. The rule is NON_COMPLIANT if a Secret is not encrypted. Optionally, specify the encryption configuration used for the Secrets.", - "Name": "Kubernetes Secrets", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "8.3.2: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "Core" } ] }, { "Id": "8.3.4.1", "Description": "Checks if a Kubernetes cluster is part of a specific organization when using a multi-tenant structure. The rule is NON_COMPLIANT if a namespace (representing an account) is not part of the defined organization or if the organization master namespace ID does not match the rule parameter MasterNamespaceId.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.4.2", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) policies that prevent the deletion of persistent volume claims. The rule is NON_COMPLIANT if the cluster does not have appropriate Role or ClusterRole bindings that include 'deny' rules for the 'delete' action on PersistentVolumeClaims.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.3.4.3", "Description": "Checks if a Kubernetes Pod has a Service Account attached to it. The rule is NON_COMPLIANT if no Service Account is associated with the Pod.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.4.4", "Description": "Checks if Kubernetes Pods have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the Pod's securityContext is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.4.5", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) policies that you create do not allow unauthorized actions on Kubernetes secrets. The rule is NON_COMPLIANT if any unauthorized action is permitted on Kubernetes secrets by the managed RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "8.3.4.6", "Description": "Checks if the RBAC (Role-Based Access Control) policies attached to your Kubernetes users, service accounts, and roles do not allow blocked actions on all Kubernetes resources. The rule is NON_COMPLIANT if any blocked action is allowed on all Kubernetes resources in an RBAC policy.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.3.4.7", "Description": "Checks if the Pod Security Policies feature is not in use. The rule is NON_COMPLIANT if a Kubernetes user, role, or group has any inline Pod Security Policies defined.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.4.8", "Description": "Checks in each Kubernetes Role or ClusterRole resource, if a RoleBinding or ClusterRoleBinding in the input parameter is applied to the Role or ClusterRole resource. The rule is NON_COMPLIANT if the RoleBinding or ClusterRoleBinding is applied to the Role or ClusterRole resource.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.9", "Description": "Checks whether the Role ARN is attached to a Kubernetes ServiceAccount, or a RoleBinding or ClusterRoleBinding with one or more ServiceAccounts, or a Pod that assumes that ServiceAccount.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.4.10", "Description": "Checks if Kubernetes Role or ClusterRole resources have rules that grant permissions to all verbs on all resources. The rule is NON_COMPLIANT if any Role or ClusterRole has a rule with 'verbs': ['*'] over 'resources': ['*'].", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.11", "Description": "Checks if Kubernetes Role or ClusterRole policies that you create grant permissions to all actions on individual Kubernetes resources. The rule is NON_COMPLIANT if any customer managed Role or ClusterRole allows full access to at least 1 Kubernetes resource.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_cluster_admin_usage" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.12", "Description": "Checks if all specified Kubernetes RoleBindings are attached to the Kubernetes ServiceAccount. The rule is NON_COMPLIANT if a RoleBinding is not attached to the ServiceAccount.", - "Name": "Kubernetes Role-Based Access Control (RBAC)", + "Name": "Role-Based Access Control (RBAC)", "Checks": [], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Role-Based Access Control (RBAC)" + "Service": "Role-Based Access Control (RBAC)" } ] }, { "Id": "8.3.4.13", "Description": "Checks if none of your Kubernetes ServiceAccounts have direct RoleBindings or ClusterRoleBindings attached. ServiceAccounts must inherit permissions from Roles or ClusterRoles. The rule is NON_COMPLIANT if there is at least one RoleBinding or ClusterRoleBinding that is directly attached to the ServiceAccount.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_plugin" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.4.14", "Description": "Checks if a Kubernetes cluster has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes cluster does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.4.15", "Description": "Checks if Kubernetes clusters have Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if RBAC is not enabled for the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.3.4.16", "Description": "Checks if a Kubernetes pod has Role-Based Access Control (RBAC) enabled. The rule is NON_COMPLIANT if a Kubernetes pod does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.17", "Description": "Checks if a Kubernetes Pod has Role-Based Access Control (RBAC) enabled for authentication and authorization. The rule is NON_COMPLIANT if a Pod does not have RBAC enabled.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.18", "Description": "Checks if Kubernetes Persistent Volumes (PVs) allow user permissions through access control policies. The rule is NON_COMPLIANT if access control is configured for user access in Kubernetes Persistent Volumes.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.19", "Description": "Checks if a Kubernetes Role or ClusterRole does not allow blocklisted permissions on resources for subjects from other namespaces. For example, the rule checks that the Role or ClusterRole does not allow another namespace to perform any 'get', 'list', or 'delete' actions on any pod resources. The rule is NON_COMPLIANT if any blocklisted actions are allowed by the Kubernetes Role or ClusterRole.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.4.20", "Description": "Verifies that access to the Kubernetes PersistentVolume (PV) is restricted by any of the Kubernetes principals, service accounts, namespaces, or network policies that you define. The rule is COMPLIANT if a role or cluster role binding is not present that grants access to the PersistentVolume.", - "Name": "Kubernetes PersistentVolume", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes PersistentVolume" + "Service": "RBAC" } ] }, { "Id": "8.3.4.21", "Description": "Checks if your Kubernetes PersistentVolumePolicies do not allow other inter-namespace permissions than the control PersistentVolumePolicy that you provide.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.4.22", "Description": "Checks if the Security Response Team (SRT) can access your Kubernetes cluster. The rule is NON_COMPLIANT if Kubernetes RBAC is enabled but the role for SRT access is not configured.", - "Name": "Kubernetes RBAC", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.4: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.5.1", "Description": "Checks if Kubernetes service account tokens are rotated within a specified time period. The rule is NON_COMPLIANT if tokens are not rotated within the specified time period. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.5: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.5.2", "Description": "Checks if Kubernetes secrets have automatic rotation enabled for their associated secrets. If a max rotation frequency is specified, it compares the configuration of the secret's rotation against this value. The rule is NON_COMPLIANT if the secret is not set to rotate automatically or if the defined rotation frequency exceeds the specified maximum.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.5: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -19039,74 +18131,74 @@ { "Id": "8.3.5.4", "Description": "Checks if Kubernetes Secrets have been updated in the past specified number of days. The rule is NON_COMPLIANT if a secret has not been updated for more than maxDaysSinceUpdate number of days. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.5: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.6.1", "Description": "Checks if the Kubernetes secrets for user authentication meet the specified requirements indicated in the parameters. The rule is NON_COMPLIANT if the secrets do not meet the specified requirements.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "8.3.6: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.3.7.1", "Description": "Checks if active Kubernetes secrets storing sensitive access credentials are refreshed or created within a specified retention period. The rule is NON_COMPLIANT if secrets are not rotated within the specified time period. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.7: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.7.2", "Description": "Checks if Kubernetes Secrets have automated rotation policies applied. The rule assesses whether secrets are configured for rotation and verifies if the rotation frequency aligns with an optional maximumAllowedRotationFrequency parameter. The rule is NON_COMPLIANT if a secret is not scheduled for rotation or if its rotation frequency exceeds the specified maximumAllowedRotationFrequency.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.7: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.7.3", "Description": "Checks if Kubernetes Secrets are updated successfully according to the defined update schedule. Kubernetes calculates the date the update should happen. The rule is NON_COMPLIANT if the date passes and the secret isn't updated.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.7: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.7.4", "Description": "Checks if Kubernetes Secrets have been updated in the past specified number of days. The rule is NON_COMPLIANT if a Secret has not been updated for more than maxDaysSinceUpdate number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.7: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, @@ -19125,220 +18217,208 @@ { "Id": "8.3.9.2", "Description": "Checks if Kubernetes Secret has a rotation policy enabled. The rule also checks an optional maxRotationFrequency parameter. If the parameter is specified, the rotation frequency of the secret is compared with the maximum allowed frequency. The rule is NON_COMPLIANT if the secret is not scheduled for rotation. The rule is also NON_COMPLIANT if the rotation frequency is higher than the specified maxRotationFrequency parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.9: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.3.9.3", "Description": "Checks if Kubernetes Secrets have been updated successfully according to a defined update schedule. The system calculates the date the update should happen. The rule is NON_COMPLIANT if the date passes and the secret isn't updated.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.3.9: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.3.9.4", "Description": "Checks if Kubernetes Secrets have been updated (rotated) in the past specified number of days. The rule is NON_COMPLIANT if a secret has not been updated for more than maxDaysSinceRotation number of days. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.3.9: Strong authentication for users and administrators is established and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.4.1.1", "Description": "Checks if Kubernetes users (specifically those with RBAC roles) have multi-factor authentication (MFA) enabled. The rule is NON_COMPLIANT if MFA is not enabled for at least one user with access to the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.4.1: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.4.1.2", "Description": "Checks if Kubernetes RBAC (Role-Based Access Control) is configured to ensure that all users accessing the Kubernetes cluster via the dashboard or CLI have multi-factor authentication (MFA) enabled for their sessions. The rule is COMPLIANT if MFA is enforced for all users.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.4.1: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.4.1.3", "Description": "Checks if your Kubernetes cluster has multi-factor authentication (MFA) enabled for securing access to the Kubernetes API server. The rule is NON_COMPLIANT if any users can access the API server without MFA.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_not_always_allow" ], "Attributes": [ { "Section": "8.4.1: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "8.4.1.4", "Description": "Checks if the Kubernetes cluster's admin user requires multi-factor authentication for access. The rule is NON_COMPLIANT if the Kubernetes admin user does not have multi-factor authentication (MFA) enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.4.1: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.4.1.5", "Description": "Checks if the equivalent of MFA Delete is enabled in the Kubernetes Persistent Volume configurations. The rule is NON_COMPLIANT if persistent volume protection mechanisms, such as Retain Reclaim Policy or Backup strategies, are not in place.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "8.4.1: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "8.4.2.1", "Description": "Checks if Kubernetes users have multi-factor authentication (MFA) enabled through API server configuration and RBAC policies. The rule is NON_COMPLIANT if MFA is not enabled for any user accessing the Kubernetes cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.4.2: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.4.2.2", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) is enforced for all users accessing the Kubernetes API server. The rule is COMPLIANT if RBAC is enabled and properly configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.4.2: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.4.2.3", "Description": "Checks if your Kubernetes cluster is configured to require multi-factor authentication (MFA) for users accessing the cluster with cluster-admin role. The rule is NON_COMPLIANT if any roles are allowed to access the cluster without MFA.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.4.2: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.4.2.4", "Description": "Checks if the Kubernetes cluster's service account that has admin privileges requires multi-factor authentication for access. The rule is NON_COMPLIANT if the service account does not have multifactor authentication (MFA) configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "8.4.2: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "8.4.2.5", - "Description": "Checks if Object Lock is enabled in the Kubernetes bucket versioning configuration using a StatefulSet. The rule is NON_COMPLIANT if Object Lock is not enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "8.4.2: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.4.3.1", "Description": "Checks if Kubernetes users have multi-factor authentication (MFA) enabled. The rule is NON_COMPLIANT if MFA is not enabled for at least one Kubernetes user.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.4.3: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.4.3.2", "Description": "Checks if Kubernetes Role-Based Access Control (RBAC) is enabled for all Kubernetes users that access the cluster through a service account. The rule is COMPLIANT if RBAC is enabled.", - "Name": "Kubernetes RBAC", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.4.3: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes RBAC" + "Service": "API Server" } ] }, { "Id": "8.4.3.3", "Description": "Checks if your Kubernetes cluster is configured to enforce role-based access control (RBAC) for sensitive operations. The rule is NON_COMPLIANT if any user or service account can perform actions with elevated privileges without proper RBAC policies in place.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_auth_mode_include_rbac" ], "Attributes": [ { "Section": "8.4.3: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "8.4.3.4", "Description": "Checks if the Kubernetes cluster administrator requires multi-factor authentication (MFA) for console access. The rule is NON_COMPLIANT if the Kubernetes admin user does not have multi-factor authentication enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.4.3: Multi-factor authentication (MFA) is implemented to secure access into the CDE.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -19357,26 +18437,26 @@ { "Id": "8.6.3.1", "Description": "Checks if Kubernetes Service Accounts have their associated tokens rotated (changed) within the number of days specified in maxTokenAge. The rule is NON_COMPLIANT if tokens are not rotated within the specified time period. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "8.6.3: Use of application and system accounts and associated authentication factors is strictly managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "8.6.3.2", "Description": "Checks if the Kubernetes secrets used for storing sensitive data, such as passwords, meet the specified security requirements indicated in the parameters. The rule is NON_COMPLIANT if the secrets do not meet the specified security standards.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "8.6.3: Use of application and system accounts and associated authentication factors is strictly managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, @@ -19395,24 +18475,24 @@ { "Id": "8.6.3.4", "Description": "Checks if Kubernetes secrets are updated successfully according to the rotation schedule. If the scheduled update date passes and the secret isn't updated, the rule is considered NON_COMPLIANT.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.6.3: Use of application and system accounts and associated authentication factors is strictly managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, { "Id": "8.6.3.5", "Description": "Checks if Kubernetes Secrets have been updated (rotated) in the past specified number of days. The rule is NON_COMPLIANT if a secret has not been updated for more than maxDaysSinceUpdate number of days. The default value is 90 days.", - "Name": "Kubernetes Secrets", + "Name": "RBAC (Role-Based Access Control)", "Checks": [], "Attributes": [ { "Section": "8.6.3: Use of application and system accounts and associated authentication factors is strictly managed.", - "Service": "Kubernetes Secrets" + "Service": "RBAC (Role-Based Access Control)" } ] }, @@ -19431,264 +18511,252 @@ { "Id": "A1.1.2.2", "Description": "Checks if Kubernetes nodes are publicly accessible. The rule is NON_COMPLIANT if the node's external IP is set and reachable from the internet.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.3", "Description": "Checks if Kubernetes persistent volume snapshots are public. The rule is NON_COMPLIANT if any Kubernetes persistent volume snapshots are public.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.4", "Description": "Checks if Kubernetes Persistent Volumes (PVs) are not publicly accessible. The rule is NON_COMPLIANT if one or more Persistent Volumes have their access modes set to ReadWriteMany with a public IP, indicating they are accessible from outside the cluster.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.5", "Description": "Checks if Kubernetes containers only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem field in the container specification is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.6", "Description": "Checks if Kubernetes Persistent Volume (PV) is configured to enforce a specific mount path and not the root directory. The rule is NON_COMPLIANT if the mount path is set to '/' (default root directory of the volume).", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.7", "Description": "Checks if Kubernetes Persistent Volumes (PVs) and Persistent Volume Claims (PVCs) are configured with appropriate access modes and security contexts to enforce user identity. The rule is NON_COMPLIANT if 'securityContext.runAsUser' is not defined or if the access mode does not match the expected user identity configuration.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.8", "Description": "Checks if a Kubernetes Service has public access settings enabled. The rule is NON_COMPLIANT if its type is not ClusterIP, or if it's of type LoadBalancer or NodePort, and exposes ports other than Port 22.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "A1.1.2.9", "Description": "Checks if the Kubernetes Pod Security Policy or Network Policy attached to the Pod resource prohibits public access. If the Pod security policy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.10", "Description": "Checks if a Kubernetes cluster snapshot (using a backup tool) is public. The rule is NON_COMPLIANT if any existing and new Kubernetes cluster snapshots is public.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "A1.1.2.11", - "Description": "Checks if the Kubernetes database instances (like those managed by a StatefulSet or Deployment) are configured to be accessible only within the cluster and not publicly exposed via a Service with type 'LoadBalancer' or 'NodePort'. The rule is NON_COMPLIANT if the external access is enabled.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.12", "Description": "Checks if Kubernetes Persistent Volume snapshots are public. The rule is NON_COMPLIANT if any existing and new Kubernetes Persistent Volume snapshots are public.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.13", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the service is exposed on a public IP or if the `externalTrafficPolicy` is set to 'Cluster' without proper Network Policy configurations.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.1.2.14", "Description": "Checks if Kubernetes Network Policies are in place to restrict unauthorized access to Pods. The rule is NON_COMPLIANT if Network Policies are not defined to limit network access to Pods in the cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.15", "Description": "Checks if the required NetworkPolicies are configured to restrict public access for the specified Kubernetes namespaces. The rule is only NON_COMPLIANT when the defined NetworkPolicies do not match the expected configurations for controlling ingress and egress traffic.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "A1.1.2.16", "Description": "Checks if the required network policies for public access are configured at the namespace level. The rule is NON_COMPLIANT if the configuration does not match one or more settings from the specified parameters (or default).", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "A1.1.2.17", "Description": "Checks if Kubernetes Services are publicly accessible. The rule is NON_COMPLIANT if a Service of type LoadBalancer or NodePort is not listed in the excludedPublicServices parameter and has access settings that allow external traffic.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "A1.1.2.18", "Description": "Checks if the Kubernetes cluster has MFA Delete equivalent enabled for resource deletion policies. The rule is NON_COMPLIANT if resource deletion policies that require enhanced authentication are not enforced.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.2.19", "Description": "Checks if your Kubernetes Secrets do not allow unauthenticated access. The rule checks the Role-Based Access Control (RBAC) permissions, the secrets configuration, and any network policies that might expose the secrets.", - "Name": "Kubernetes Secrets", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Secrets" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.20", "Description": "Checks if your Kubernetes Persistent Volume Claims (PVCs) do not allow public write access. The rule checks the StorageClass settings, the PVC configurations, and the associated Access Modes.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.2.21", "Description": "Checks if direct internet access is disabled for a Kubernetes Pod. The rule is NON_COMPLIANT if the Pod is configured to use an External IP for internet access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.2: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -19707,338 +18775,338 @@ { "Id": "A1.1.3.1", "Description": "Checks if Kubernetes Services are of the type specified in the rule parameter serviceType. The rule returns NON_COMPLIANT if the Service does not match the endpoint type configured in the rule parameter.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "A1.1.3.2", "Description": "Checks if a Kubernetes Ingress resource is configured to use HTTPS with an SSL certificate. The rule is NON_COMPLIANT if the Ingress does not have an associated TLS configuration with a valid certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "A1.1.3.3", "Description": "Checks if Kubernetes APIs (such as those provided by the API server) are protected by Network Policies. The rule is NON_COMPLIANT for a Kubernetes API if it is not associated with a Network Policy.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "A1.1.3.4", "Description": "Checks if Kubernetes Ingress resources have a valid annotation for a Web Application Firewall (WAF) or a specific WAF ACL. The rule is NON_COMPLIANT if an Ingress resource is not associated with a WAF configuration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.5", "Description": "Checks if the certificate associated with an Ingress resource in Kubernetes is the default SSL certificate. The rule is NON_COMPLIANT if an Ingress resource uses the default SSL certificate.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "A1.1.3.6", "Description": "Checks if the Bitbucket source repository URL contains sign-in credentials; marked as NON_COMPLIANT if the URL contains any sign-in information and COMPLIANT if it doesn't.", - "Name": "Bitbucket", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Bitbucket" + "Service": "Core" } ] }, { "Id": "A1.1.3.7", "Description": "Checks if Kubernetes pods have public network access. The rule is NON_COMPLIANT if the 'hostNetwork' field is set to true in the pod specification.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.8", "Description": "Checks if Kubernetes stateful sets have public access. The rule is NON_COMPLIANT if any Kubernetes stateful sets have public network policies, exposing them to the internet.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.9", "Description": "Checks if the Kubernetes NetworkPolicy allows access for all pods. The rule is NON_COMPLIANT if 'allow all' is present and set to true.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "A1.1.3.10", "Description": "Checks if the status of the Kubernetes Deployment rollout is successful or failed after the deployment update on the pod. The deployment is compliant if the status indicates success. For more information about deployments, see What is a deployment?", - "Name": "Kubernetes Deployment", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Deployment" + "Service": "Core" } ] }, { "Id": "A1.1.3.11", "Description": "Checks if Kubernetes Network Policies have 'ingress' rules defined to allow traffic. The rule is NON_COMPLIANT for a Network Policy if 'ingress' rules are not configured.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "A1.1.3.12", "Description": "Checks if the Kubernetes cluster endpoint is not publicly accessible. The rule is NON_COMPLIANT if the endpoint is publicly accessible.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.1.3.13", "Description": "Checks if Kubernetes clusters have their services configured with private access only. The rule is NON_COMPLIANT if a service exposed is of type LoadBalancer and is accessible from outside the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.1.3.14", "Description": "Checks if Ingress resources in Kubernetes are configured with certificates from a Certificate Manager. This rule is NON_COMPLIANT if at least 1 Ingress resource has at least 1 TLS configuration that is not using a certificate from the designated Certificate Manager or is configured with a certificate different from the designated Certificate Manager's certificate.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [ "apiserver_kubelet_cert_auth" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, { "Id": "A1.1.3.15", "Description": "Checks if the Kubernetes Services use TLS certificates provided by a specified certificate management solution (e.g., cert-manager). To use this rule, ensure that the Service is configured with a TLS or HTTPS endpoint. This rule is only applicable to Kubernetes Services configured for TLS. This rule does not check Ingress resources or any other types of Services.", - "Name": "Kubernetes Service", + "Name": "API Server", "Checks": [ "apiserver_tls_config" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Service" + "Service": "API Server" } ] }, { "Id": "A1.1.3.16", "Description": "Checks if a Kubernetes cluster has network policies that restrict public access. The rule is NON_COMPLIANT if NetworkPolicy is not applied, or if applied, ports other than Port 22 are open in the allowed ingress or egress rules.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.17", "Description": "The rule INCOMING_SSH_DISABLED named restricted-ssh restricts incoming SSH connections to enhance security in Kubernetes.", - "Name": "networkpolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "networkpolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.18", "Description": "Checks if Load Balancers are associated with an authorized Kubernetes cluster. The rule is NON_COMPLIANT if Load Balancers are associated with an unauthorized cluster.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.19", "Description": "Checks if the Kubernetes Service policy attached to the Service resource prohibits public access. If the Service policy allows public access, it is NON_COMPLIANT.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "A1.1.3.20", "Description": "Checks if a Kubernetes Pod is allowed access to a virtual private cloud (VPC) through the presence of network policies. The rule is NON_COMPLIANT if the Pod is not configured with the correct network policies for VPC access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.21", "Description": "Checks if Kubernetes Network Policies allow unrestricted ingress traffic on default ports for SSH (22) or RDP (3389). The rule is NON_COMPLIANT if a Network Policy permits ingress traffic from any source IP to these ports.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "A1.1.3.22", "Description": "Checks if a Kubernetes Network Policy is configured with a user-defined default action for fragmented packets. The rule is NON_COMPLIANT if the default action for fragmented packets does not match with the user-defined default action.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "A1.1.3.23", "Description": "Check if the Kubernetes NetworkPolicy is associated with ingress or egress rules. This policy is NON_COMPLIANT if no ingress or egress rules are defined in the NetworkPolicy, otherwise COMPLIANT if at least one rule exists.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.24", "Description": "Checks if a Kubernetes NetworkPolicy contains ingress or egress rules. The policy is NON_COMPLIANT if there are no rules defined in the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.25", "Description": "Checks if there are public routes in the Kubernetes NetworkPolicy to an external service. The rule is NON_COMPLIANT if a NetworkPolicy allows traffic to a specific service from any source without restrictions.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.26", "Description": "Checks if Kubernetes clusters are within a Virtual Private Cloud (VPC). The rule is NON_COMPLIANT if a Kubernetes service is exposed with type 'LoadBalancer' or 'NodePort' without proper network policies restricting access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.27", "Description": "Checks if there are any Kubernetes Network Policies that do not conform to the default network policy. The rule is NON_COMPLIANT if there are any network policies that are not the default network policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -20057,252 +19125,252 @@ { "Id": "A1.1.3.29", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the publicly accessible fields in the cluster configuration (e.g., `--advertise-address`, `--enable-aggregator-routing`, security group settings) are set to allow public access.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.30", "Description": "Checks if Kubernetes services have network policies that deny public access. The rule is NON_COMPLIANT if network policies do not restrict public access to the services.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.1.3.31", "Description": "Verifies that the public access settings for Kubernetes resources (such as Pods or Services) are correctly configured at the cluster level. The rule is considered NON_COMPLIANT if the specified settings for public access do not align with the designated configuration specifications.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.1.3.32", "Description": "Checks if the required network policies are configured to restrict public access at the namespace level. The rule is NON_COMPLIANT if the network policy does not match one or more settings from parameters or defaults.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "A1.1.3.33", "Description": "Checks if Kubernetes Services are publicly accessible. The rule is NON_COMPLIANT if a Service is of type 'LoadBalancer' or 'NodePort' and is not listed in the excludedPublicServices parameter, and the service level settings are public.", - "Name": "Kubernetes Services", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Services" + "Service": "API Server" } ] }, { "Id": "A1.1.3.34", "Description": "Checks if your Kubernetes persistent volume claims do not allow public access. The rule checks the access modes and any associated Network Policies or Role-Based Access Control (RBAC) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A1.1.3.35", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public write access. The rule checks the Persistent Volume Claims and their associated access modes, ensuring that only authorized users can write to the volumes.", - "Name": "Kubernetes Persistent Volumes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Persistent Volumes" + "Service": "RBAC" } ] }, { "Id": "A1.1.3.36", "Description": "Checks if a Kubernetes Pod is deployed within a specific namespace or within a list of approved namespaces. The rule is NON_COMPLIANT if a Pod is not deployed within a specified namespace or if its namespace is not included in the parameter list.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.37", "Description": "Checks if direct internet access is disabled for a Kubernetes Pod. The rule is NON_COMPLIANT if a Pod is configured to use an external IP or has access to the internet through its network settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.38", "Description": "Checks if a Kubernetes Service has Endpoints created for each corresponding Deployment or Pod in the specified namespace. The rule is NON_COMPLIANT if any Deployment or Pod does not have the corresponding Endpoints for the Service.", - "Name": "Kubernetes Service", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Service" + "Service": "Core" } ] }, { "Id": "A1.1.3.39", "Description": "Checks if there are unused Network Policies. The rule is COMPLIANT if each Network Policy is associated with a Pod. The rule is NON_COMPLIANT if a Network Policy is not associated with a Pod.", - "Name": "NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.40", "Description": "In Kubernetes, equivalent configuration checks would involve validating Network Policies to ensure that only specified pods can accept incoming traffic on certain ports. The check is NON_COMPLIANT if there are Network Policies allowing unrestricted traffic on all ports without specifying authorized ports.", - "Name": "Kubernetes Networking", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes Networking" + "Service": "Core" } ] }, { "Id": "A1.1.3.41", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The NetworkPolicy is NON_COMPLIANT if there are no rules specified within it.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.42", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if no rules are present within the NetworkPolicy.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.43", "Description": "Checks whether a Kubernetes NetworkPolicy exists in a namespace. This rule is NON_COMPLIANT if a NetworkPolicy does not exist, as it is recommended to enforce network segmentation.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.44", "Description": "Checks if Kubernetes Network Policies contain any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within a Kubernetes Network Policy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.1.3.45", "Description": "Checks whether a Kubernetes NetworkPolicy contains ingress or egress rules. This NetworkPolicy is COMPLIANT if it includes at least one rule and NON_COMPLIANT otherwise.", - "Name": "Kubernetes NetworkPolicy", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes NetworkPolicy" + "Service": "API Server" } ] }, { "Id": "A1.1.3.46", "Description": "Checks if a Kubernetes NetworkPolicy contains any ingress or egress rules. The policy is NON_COMPLIANT if there are no rules present within the NetworkPolicy.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.1.3: Multi-tenant service providers protect and separate all customer environments and data.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.1", "Description": "Checks if Kubernetes Ingress resources have access logging enabled. The rule is NON_COMPLIANT if an access log configuration is not defined for the Ingress resource.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "A1.2.1.2", "Description": "Checks if all methods in Kubernetes Ingress resources have logging enabled. The rule is NON_COMPLIANT if logging is not enabled or if the logging level is neither ERROR nor INFO.", - "Name": "Ingress Controller", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Ingress Controller" + "Service": "API Server" } ] }, @@ -20321,212 +19389,198 @@ { "Id": "A1.2.1.4", "Description": "Checks if a Kubernetes API server has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled, or 'audit-log-path' is set to a path that does not exist or is not configured correctly.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "A1.2.1.5", "Description": "Checks if Kubernetes Services are configured with a user-defined session affinity. The rule is NON_COMPLIANT if the session affinity setting does not match the user-defined session affinity mode.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Services" + "Service": "Core" } ] }, { "Id": "A1.2.1.6", "Description": "Checks if Kubernetes Ingress resources are configured to log requests to a designated logging service. The rule is NON_COMPLIANT if an Ingress resource does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "A1.2.1.7", "Description": "Checks if at least one Kubernetes audit policy is logging data events for all resources in the cluster. The rule is NON_COMPLIANT if there are no policies in place that record data events.", - "Name": "Kubernetes Audit Logging", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "A1.2.1.8", "Description": "Checks that there is at least one Kubernetes audit policy defined with security best practices. This rule is COMPLIANT if there is at least one audit policy that meets all of the following: proper event retention, appropriate level of information logged, and compliance with organizational security requirements.", - "Name": "Kubernetes Audit", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Audit" + "Service": "API Server" } ] }, { "Id": "A1.2.1.9", "Description": "Checks if Kubernetes Secrets are encrypted at rest with a specified encryption configuration. The rule is NON_COMPLIANT if a Secret is not encrypted or is encrypted with a key not specified in the encryption configuration.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "A1.2.1.10", - "Description": "In Kubernetes, the equivalent concept would be to ensure that audit logs are enabled for the cluster, similar to how AWS CloudTrail enables logging for account activity. This involves configuring the audit logging feature in Kubernetes to track and log requests to the API server.", - "Name": "Kubernetes", - "Checks": [ - "apiserver_audit_log_path_set" - ], - "Attributes": [ - { - "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.11", "Description": "Checks if the Kubernetes cluster has encryption enabled for secrets, using the specific encryption provider. The rule is COMPLIANT if the encryption provider is configured in the Kubernetes API server with an encryption config file.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_encryption_provider_config_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.12", "Description": "Checks if Kubernetes audit logging is enabled and if the logs are being stored securely. It's recommended that audit logging is configured to capture all events for compliance and security purposes. The rule is NON_COMPLIANT if audit logging is not enabled or misconfigured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.13", "Description": "Checks if a Kubernetes Pod has at least one logging option enabled. The rule is NON_COMPLIANT if the status of all present logging configurations is set to 'DISABLED'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.14", "Description": "Checks if logging is enabled with a valid severity level for Kubernetes pod events. The rule is NON_COMPLIANT if logging is not enabled or pod logging does not have a severity level that is not valid.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.15", "Description": "Verifies whether a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.16", "Description": "Checks if a Kubernetes cluster has logging enabled for its API server. The rule is NON_COMPLIANT if 'apiServer.logging.enabled' is set to false.", - "Name": "Kubernetes API Server", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes API Server" + "Service": "API Server" } ] }, { "Id": "A1.2.1.17", "Description": "Checks if the logging configuration is set on active Kubernetes Pod specifications. This rule is NON_COMPLIANT if an active Pod does not have the logging configuration resource defined or the value for logging configuration is null in at least one container specification.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.18", "Description": "Checks if a Kubernetes cluster is configured with logging enabled. The rule is NON_COMPLIANT if logging for Kubernetes clusters is not enabled for all log types, including application logs, audit logs, and container logs.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.19", "Description": "Checks if Kubernetes clusters are configured to send logs to a logging solution such as Fluentd or Fluent Bit. The rule is NON_COMPLIANT if logging is not properly set up or if log forwarding is disabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -20545,256 +19599,244 @@ { "Id": "A1.2.1.21", "Description": "Checks if Kubernetes pods have logging enabled for monitoring purposes. The rule is NON_COMPLIANT if a pod does not have appropriate logging configuration enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.22", "Description": "Checks if a Kubernetes cluster has audit logging enabled. The rule is NON_COMPLIANT if audit logging is not enabled for the cluster.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "A1.2.1.23", - "Description": "The rule identifier MULTI_REGION_CLOUD_TRAIL_ENABLED corresponds to the rule name multi-region-cloudtrail-enabled, indicating that a multi-region CloudTrail is enabled for tracking events across different regions.", - "Name": "AWS CloudTrail", - "Checks": [], - "Attributes": [ - { - "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "AWS CloudTrail" + "Service": "API Server" } ] }, { "Id": "A1.2.1.24", "Description": "Checks if a Kubernetes cluster has logging enabled for audit logs. The rule is NON_COMPLIANT if the Kubernetes cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.25", "Description": "Checks if Kubernetes Network Policies have logging enabled. The rule is NON_COMPLIANT if a logging type is not configured. You can specify which logging type you want the rule to check.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "A1.2.1.26", "Description": "Checks if Kubernetes clusters have logging configured to capture audit logs and are publishing them to a logging service such as Elasticsearch or a monitoring tool like Prometheus. The rule is NON_COMPLIANT if Kubernetes clusters do not have audit log publishing configured.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.27", "Description": "Checks if the respective logs of Kubernetes pods are enabled. The rule is NON_COMPLIANT if any logs are not enabled for the pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.28", "Description": "Checks if Kubernetes clusters are logging audit events to a specific location. The rule is NON_COMPLIANT if audit logging is not enabled for a Kubernetes cluster or if the 'auditLogPath' parameter is provided but the logging destination does not match.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.29", "Description": "Checks if Kubernetes clusters have the specified settings. The rule is NON_COMPLIANT if the Kubernetes cluster is not encrypted or encrypted with another key, or if a cluster does not have audit logging enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.30", "Description": "Checks if DNS query logging is enabled for your Kubernetes cluster's CoreDNS configuration. The rule is NON_COMPLIANT if DNS query logging is not enabled.", - "Name": "CoreDNS", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "CoreDNS" + "Service": "Core" } ] }, { "Id": "A1.2.1.31", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and the service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A1.2.1.32", "Description": "Checks if logging is enabled for your Kubernetes cluster's persistent volumes. The rule is NON_COMPLIANT if logging is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.33", "Description": "Checks if Kubernetes Pods have logging enabled. The rule is NON_COMPLIANT if a Pod does not have logging enabled or the logging configuration is not at the minimum level required.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.34", "Description": "Checks if Kubernetes Network Policies are defined and enforced for all namespaces. The rule is NON_COMPLIANT if network policies are not defined for at least one namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A1.2.1.35", "Description": "Checks if logging is enabled on Kubernetes network policies. The rule is NON_COMPLIANT if the logging is enabled but the logging destination does not match the expected value for the network policies.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "A1.2.1.36", "Description": "Checks if logging is enabled on Kubernetes Ingress resources. The rule is NON_COMPLIANT for an Ingress resource if it does not have logging enabled.", - "Name": "Kubernetes Ingress", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A1.2.1: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes Ingress" + "Service": "API Server" } ] }, { "Id": "A1.2.3.1", "Description": "Checks if security contact information is provided for Kubernetes cluster administrators. The rule is NON_COMPLIANT if security contact information for cluster administrators is not configured.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A1.2.3: Multi-tenant service providers facilitate logging and incident response for all customers.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.2.5.1.1", "Description": "Checks if automated sensitive data discovery is enabled in Kubernetes. The rule is NON_COMPLIANT if automated sensitive data discovery is disabled. The rule is APPLICABLE for cluster administrator roles and NOT_APPLICABLE for regular user roles.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.2.5.1: PCI DSS scope is documented and validated.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.2.5.1.2", "Description": "Checks if a specific Kubernetes PodSecurityPolicy is enabled in your cluster. The rule is NON_COMPLIANT if the 'privileged' attribute is set to 'true'.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "A3.2.5.1: PCI DSS scope is documented and validated.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A3.2.5.1.3", "Description": "Checks if automated sensitive data discovery is enabled for Kubernetes Secrets Management. The rule is NON_COMPLIANT if automated sensitive data discovery for secrets is disabled. The rule is APPLICABLE for administrator accounts and NOT_APPLICABLE for regular user accounts.", - "Name": "Kubernetes Secrets Management", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "A3.2.5.2: PCI DSS scope is documented and validated.", - "Service": "Kubernetes Secrets Management" + "Service": "RBAC" } ] }, @@ -20813,110 +19855,74 @@ { "Id": "A3.3.1.1", "Description": "Checks if OpenTelemetry tracing is enabled on Kubernetes Services. The rule is COMPLIANT if OpenTelemetry tracing is enabled for the Service and NON_COMPLIANT otherwise.", - "Name": "Kubernetes Services", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes Services" - } - ] - }, - { - "Id": "A3.3.1.2", - "Description": "Checks if your Kubernetes resources (like Deployments or StatefulSets) have proper event notifications configured to send alerts to a specified messaging system (e.g., Slack, Email). Optionally checks if specified notification channels are used. The rule is NON_COMPLIANT if Kubernetes resources do not send notifications.", - "Name": "Kubernetes", - "Checks": [], - "Attributes": [ - { - "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.3.1.3", "Description": "Checks if Kubernetes alerts (e.g., from Prometheus or other monitoring tools) have an action configured in response to specific alert states (e.g., firing, pending, resolved). Optionally checks if any actions match a specified named resource. The rule is NON_COMPLIANT if no action is specified for the alert or the optional parameter.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "A3.3.1.4", - "Description": "Checks if a Kubernetes resource type has a Prometheus alert for the named metric. For resource type, you can specify Pods, Deployments, Services, or StatefulSets. The rule is COMPLIANT if the named metric has a resource ID and Prometheus alert.", - "Name": "Prometheus", - "Checks": [], - "Attributes": [ - { - "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Prometheus" + "Service": "Core" } ] }, { "Id": "A3.3.1.5", "Description": "Checks whether Kubernetes events with the given metric name have the specified settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.3.1.6", "Description": "Checks if Kubernetes audit logging is configured to send logs to a designated logging service (like Elasticsearch, Fluentd, or a specified log aggregation service). The audit configuration is NON_COMPLIANT if the log output destination is not set or is empty.", - "Name": "Kubernetes Audit Logging", + "Name": "API Server", "Checks": [ "apiserver_audit_log_path_set" ], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes Audit Logging" + "Service": "API Server" } ] }, { "Id": "A3.3.1.7", "Description": "Checks if detailed monitoring (similar to Kubernetes 'prometheus') is enabled for Pods. The rule is NON_COMPLIANT if detailed monitoring is not enabled (i.e., the Prometheus metrics are not collected).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.3.1.8", "Description": "Checks if Kubernetes Event Notifications are enabled for a specified resource (like a Pod). The rule is NON_COMPLIANT if Event Notifications are not set on the resource, or if the event type or destination do not match the expected criteria.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes" - } - ] - }, - { - "Id": "A3.3.1.9", - "Description": "Checks if AWS Security Hub is enabled for an AWS Account. The rule is NON_COMPLIANT if AWS Security Hub is not enabled.", - "Name": "AWS Security Hub", - "Checks": [], - "Attributes": [ - { - "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "AWS Security Hub" + "Service": "Core" } ] }, @@ -20935,174 +19941,174 @@ { "Id": "A3.3.1.11", "Description": "Checks if the monitoring metrics collection is enabled for a Kubernetes network policy. The policy is NON_COMPLIANT if the 'metrics.enabled' field is set to false.", - "Name": "Kubernetes Network Policy", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.3.1: PCI DSS is incorporated into business-as-usual (BAU) activities.", - "Service": "Kubernetes Network Policy" + "Service": "Core" } ] }, { "Id": "A3.4.1.1", "Description": "Checks if a Kubernetes Namespace has an attached resource-based policy (in this case, RoleBindings or ClusterRoleBindings) that prevents deletion of resources. The rule is NON_COMPLIANT if the Namespace does not have resource-based policies or has policies without a suitable 'deny' rule for deletion actions (such as delete pods, delete deployments, etc.).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.2", "Description": "Checks if Kubernetes pods have public IPs. The rule is NON_COMPLIANT if the pod spec contains a host network configuration with hostNetwork set to true, allowing the pod to use the node's network namespace.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_hostNetwork_containers" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.3", "Description": "Checks if Kubernetes Persistent Volume backups are public. The rule is NON_COMPLIANT if any Kubernetes Persistent Volume backups are public.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.4", "Description": "Checks if Kubernetes Persistent Volume (PV) snapshots are not publicly accessible. The rule is NON_COMPLIANT if one or more Persistent Volumes are configured to allow access from all users or unauthorized entities, meaning the snapshots are public.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.5", "Description": "Checks if Kubernetes Pods only have read-only access to their root filesystems. The rule is NON_COMPLIANT if the readOnlyRootFilesystem parameter in the securityContext of a PodSpec is set to 'false'.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_root_containers_admission" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.6", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) use a defined access mode to enforce a specific root directory for storage. The rule is NON_COMPLIANT if the access mode allows unrestricted access to the entire file system.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.7", "Description": "Checks if Kubernetes Persistent Volume Claims (PVCs) are configured to enforce a specific user identity through security contexts. The rule is NON_COMPLIANT if 'runAsUser' is not defined in the security context or if parameters are provided and there is no match in the corresponding security parameters.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.8", "Description": "Checks if a Kubernetes cluster has network policies that restrict public access. The rule is NON_COMPLIANT if there are network policies allowing traffic from public IPs to any ports other than those specified in the allowed list (e.g., port 22 for SSH).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.9", "Description": "Checks whether Kubernetes namespaces have at least one service account.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_service_account_lookup_true" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A3.4.1.10", "Description": "Checks if your Kubernetes service accounts have tokens or access credentials that have not been used within the specified number of days you provided. The rule is NON_COMPLIANT if there are inactive accounts not recently used.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.11", "Description": "Checks if the Kubernetes Role-Based Access Control (RBAC) permissions for the Service Account attached to the Pod prohibit public access. If the Service Account permissions allow public access, it is NON_COMPLIANT.", - "Name": "Kubernetes RBAC", + "Name": "RBAC", "Checks": [ "rbac_minimize_pod_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes RBAC" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.12", "Description": "Checks if a Kubernetes database (like PostgreSQL or MySQL) snapshot is public. The rule is NON_COMPLIANT if any existing and new database snapshot is public.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, @@ -21121,160 +20127,160 @@ { "Id": "A3.4.1.14", "Description": "Checks if any Kubernetes Persistent Volume (PV) claims are publicly accessible. The rule is NON_COMPLIANT if any existing and new Kubernetes Persistent Volumes are exposed to the public.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.15", "Description": "Checks if Kubernetes clusters are not publicly accessible. The rule is NON_COMPLIANT if the service is exposed with a LoadBalancer type service in the service configuration.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A3.4.1.16", "Description": "Checks if Kubernetes Secrets have confidential data protection settings enabled. The rule is NON_COMPLIANT if confidential data protection settings are not enabled for Kubernetes Secrets.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_no_secrets_envs" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.17", "Description": "Checks if the required network policies are configured to restrict public access at the cluster level. The rule is only NON_COMPLIANT when the network policies set below do not match the corresponding rules in the configuration item.", - "Name": "Kubernetes Network Policies", + "Name": "API Server", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes Network Policies" + "Service": "API Server" } ] }, { "Id": "A3.4.1.18", "Description": "Checks if the necessary network policies and ingress settings are configured for the Kubernetes cluster to ensure proper access management and security. The rule is NON_COMPLIANT if the configuration does not match one or more required settings.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [ "core_minimize_admission_hostport_containers" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.19", "Description": "Checks if Kubernetes services are publicly accessible. The rule is NON_COMPLIANT if a Kubernetes service is not listed in the excludedPublicServices parameter and service type is LoadBalancer or NodePort.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_deny_service_external_ips" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A3.4.1.20", "Description": "Checks if the Kubernetes Cluster has MFA Delete equivalent configurations for enhanced security measures on persistent storage. The rule is NON_COMPLIANT if there are no similar restrictions or security policies enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.21", "Description": "Checks if your Kubernetes Persistent Volumes do not allow public read access. The rule checks the Persistent Volume policies, the access modes, and the role-based access control (RBAC) settings.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.22", "Description": "Checks if your Kubernetes Persistent Volumes (PVs) do not allow public write access. The rule verifies the access modes, resource quotas, and network policies associated with the persistent storage in the cluster.", - "Name": "Kubernetes", + "Name": "RBAC", "Checks": [ "rbac_minimize_pv_creation_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "RBAC" } ] }, { "Id": "A3.4.1.23", "Description": "Checks if direct internet access is disabled for a Kubernetes pod. The rule is NON_COMPLIANT if a pod has access to the internet through an external network policy or if it is deployed in a way that allows external traffic (e.g., using LoadBalancer service type).", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.24", "Description": "Checks if Kubernetes Secrets have been accessed within a specified number of days. The rule is NON_COMPLIANT if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.4.1.25", "Description": "Checks if Kubernetes ConfigMaps created by the namespace are publicly accessible. The rule is NON_COMPLIANT if ConfigMaps with owner 'kube-system' are accessible without proper role-based access control (RBAC) settings.", - "Name": "Kubernetes ConfigMap", + "Name": "RBAC", "Checks": [ "rbac_minimize_secret_access" ], "Attributes": [ { "Section": "A3.4.1: Logical access to the cardholder data environment is controlled and managed.", - "Service": "Kubernetes ConfigMap" + "Service": "RBAC" } ] }, @@ -21293,122 +20299,110 @@ { "Id": "A3.5.1.2", "Description": "Checks if your Kubernetes deployments send event notifications to a specified monitoring service like Prometheus or an external alert manager. Optionally checks if specified notification channels (like Slack or email) are configured for alerts. The rule is NON_COMPLIANT if Kubernetes deployments do not send notifications.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.3", "Description": "Checks if Kubernetes alerts (such as Prometheus Alertmanager alerts) have an action configured for firing, pending, or resolved states. Optionally checks if any actions match a named identifier. The rule is NON_COMPLIANT if there is no action specified for the alert or optional parameter.", - "Name": "Prometheus", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Prometheus" - } - ] - }, - { - "Id": "A3.5.1.4", - "Description": "Checks if a Kubernetes resource type (such as Pods, Deployments, StatefulSets, or PersistentVolumes) has a Prometheus alert for a specified metric. The rule is COMPLIANT if the named metric has a corresponding resource identifier and Prometheus alert.", - "Name": "Prometheus", - "Checks": [], - "Attributes": [ - { - "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Prometheus" + "Service": "Core" } ] }, { "Id": "A3.5.1.5", "Description": "Checks whether Kubernetes alerts configured via Prometheus have the specified settings for the given metric name.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.6", "Description": "Checks if Kubernetes logging is configured to send logs to a centralized logging system (e.g., Elasticsearch, Fluentd, etc.). The logging is CONCERNED if the logging configuration of the pod does not specify a destination for the logs.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.7", "Description": "Checks if detailed monitoring is enabled for Kubernetes pods. The rule is NON_COMPLIANT if detailed monitoring is not enabled for the pods.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.8", "Description": "Checks if Kubernetes Event Notifications are enabled for a specific resource (e.g., Pod, Deployment). The rule is NON_COMPLIANT if Event Notifications (via a specific service like Kubernetes Events or another notification system) are not set for a resource, or if the type of event or destination does not match the specified event types and destination parameters.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.9", "Description": "Checks if a specific Kubernetes security feature (like Pod Security Policies or Network Policies) is enabled in a Kubernetes cluster. The rule is NON_COMPLIANT if the feature is not enabled.", - "Name": "Kubernetes", + "Name": "API Server", "Checks": [ "apiserver_security_context_deny_plugin" ], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "API Server" } ] }, { "Id": "A3.5.1.10", "Description": "Checks if Kubernetes Event Logging is enabled for the delivery status of notification messages sent to a specific service for the endpoints. The rule is NON_COMPLIANT if the delivery status notification for messages is not enabled.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] }, { "Id": "A3.5.1.11", "Description": "Checks if the Prometheus monitoring is enabled for Kubernetes deployments. The deployment is NON_COMPLIANT if the 'spec.template.spec.containers[].resources.limits.cpu' or 'spec.template.spec.containers[].resources.limits.memory' fields are not set, indicating that resource limits are not monitored.", - "Name": "Kubernetes", + "Name": "Core", "Checks": [], "Attributes": [ { "Section": "A3.5.1: Suspicious events are identified and responded to.", - "Service": "Kubernetes" + "Service": "Core" } ] } diff --git a/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py b/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py index 7bfc89cae0..6f3d044ff2 100644 --- a/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py +++ b/tests/providers/aws/services/route53/route53_public_hosted_zones_cloudwatch_logging_enabled/route53_public_hosted_zones_cloudwatch_logging_enabled_test.py @@ -145,12 +145,15 @@ class Test_route53_public_hosted_zones_cloudwatch_logging_enabled: ), } - with mock.patch( - "prowler.providers.aws.services.route53.route53_service.Route53", - new=route53, - ), mock.patch( - "prowler.providers.aws.services.route53.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_client", - new=route53, + with ( + mock.patch( + "prowler.providers.aws.services.route53.route53_service.Route53", + new=route53, + ), + mock.patch( + "prowler.providers.aws.services.route53.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_client", + new=route53, + ), ): # Test Check from prowler.providers.aws.services.route53.route53_public_hosted_zones_cloudwatch_logging_enabled.route53_public_hosted_zones_cloudwatch_logging_enabled import ( From e6cdda1bd9a199425aa8871fd24bbb98ba804dd5 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 19 Mar 2025 14:46:11 +0545 Subject: [PATCH 039/359] chore(dependabot): Disable for API and UI (#7300) --- .github/dependabot.yml | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index dee1ed1f62..e535e897ce 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,16 +16,17 @@ updates: - "dependencies" - "pip" - - package-ecosystem: "pip" - directory: "/api" - schedule: - interval: "daily" - open-pull-requests-limit: 10 - target-branch: master - labels: - - "dependencies" - - "pip" - - "component/api" + # Dependabot Updates are temporary disabled - 2025/03/19 + # - package-ecosystem: "pip" + # directory: "/api" + # schedule: + # interval: "daily" + # open-pull-requests-limit: 10 + # target-branch: master + # labels: + # - "dependencies" + # - "pip" + # - "component/api" - package-ecosystem: "github-actions" directory: "/" @@ -37,16 +38,17 @@ updates: - "dependencies" - "github_actions" - - package-ecosystem: "npm" - directory: "/ui" - schedule: - interval: "daily" - open-pull-requests-limit: 10 - target-branch: master - labels: - - "dependencies" - - "npm" - - "component/ui" + # Dependabot Updates are temporary disabled - 2025/03/19 + # - package-ecosystem: "npm" + # directory: "/ui" + # schedule: + # interval: "daily" + # open-pull-requests-limit: 10 + # target-branch: master + # labels: + # - "dependencies" + # - "npm" + # - "component/ui" - package-ecosystem: "docker" directory: "/" From 716c8c1a5f6acb5e1f3bcc415402e3c67ce9f610 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 19 Mar 2025 12:31:37 +0100 Subject: [PATCH 040/359] docs: add social login images and update documentation (#7314) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Víctor Fernández Poyatos --- .../img/social-login/social_login_buttons.png | Bin 0 -> 239059 bytes .../social_login_buttons_disabled.png | Bin 0 -> 240843 bytes docs/tutorials/prowler-app-social-login.md | 52 ++++++++++++++++++ docs/tutorials/prowler-app.md | 12 ++++ mkdocs.yml | 39 ++++++------- 5 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 docs/tutorials/img/social-login/social_login_buttons.png create mode 100644 docs/tutorials/img/social-login/social_login_buttons_disabled.png create mode 100644 docs/tutorials/prowler-app-social-login.md diff --git a/docs/tutorials/img/social-login/social_login_buttons.png b/docs/tutorials/img/social-login/social_login_buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..476081e0fc9630e97b0d59b75734e739c8f60a2d GIT binary patch literal 239059 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
    asoi(hee| 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 F$yWCJ(oLJNjGlGz;shoH~*VvGk={h%rj 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 KtX;=``o92j&whRY literal 0 HcmV?d00001 diff --git a/docs/tutorials/img/social-login/social_login_buttons_disabled.png b/docs/tutorials/img/social-login/social_login_buttons_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..7b11a7802d3307b4aaf94babea265696df246e78 GIT binary patch literal 240843 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𝔒&hB6gj&-wrt#|uFyl>5dMs4N(wK(U4~A# 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
    Md&qA%|_+u&R8l14Un8DmYLcr(Es zA66vkcvq0+)A->t$F-Om{MDH4`!N=8kv#4ch*lKp>g&_(;4FLls&%S;iI>Ju)3E72 zIF^G&?!qBMIBaPwCt;HJW|A^QMupGvQMk<5e6lJ^FHVJCy;-ePBeea!0I5MOA4~Tg zY(Xo&eM-aZn3E7iv7mb3&n?EM1;O zI?h?atz%t4SPl|D#6Ii69jwwNVmNv`OD1NUn@!CP!;wa$q)T*o@?=OOqjsd*PTF@z zG`#D*saM_{S4jqsUCo29DolQ z9WXEL9g>AXBA^)JQt%0*|0oME4=f9&!VMsf2jE9o)Bs}1XVY#7ZQ>mRs813OI;7`Qz371 zJpow>Vz1PNb#lQ;{uT~3C}CzXF~BEbkC|$m;uf{RwTFL|xD>*m^A9>H0=N$#Yqi{g zll>&o5%za&(nv}|q8hCouuyhdRIdbwDVOJ(;ch)p1z-}u|DFYKN}&G+w311`ydZXp z5pHw0#k8fr&pTmZ9c49@EC7}%LtvH)f%gd)pb^-AC+VCLjxj#hFn>l{ua>VPgL zV4ws9K>In}6m?lq_it41s=^i3=y2pz3QQM-BJlKPXFoS)T|Ue;)k2?@!Vclgpdc`9 zoRuzlk;(FIZ9w*R0E|j20SQ3fTT`I!zLZL6&?h7r1f=Av+3VUV+<}BhBtLKqK&hdu z)@{$z_5(bxC&?Ic|1X~dCMu_Za1BtB0O=_XXpy)sX{-o&_~-Ob!Qd01PNJ1zx^(Q$ zspXu?N3{Sc$K%RAWi>C-M95YrBtRC1Sg1z2C9df9hfLTGS@lq3aI&FZIRU-itqE|z zbYZ`S-WvFqfgGvMeuxEhCneAqNM#rkfcXJHky7a@sk9#g%qRhU6$(xA)RT=&Xu8p8$55o8vv+hvvhoDNy-vNO&`*~$M`+}9!+dP!IOG_ zd`FXQ410GM*#bl#-Sk9zo849I20t#u3nges#j2y6U0$pcIxS?Pme?|AzG z0VhyRp08g?mNBjCJ3V2hAH@EY%)PTk9CkMQNL#xhgzlX#sSH~k8RC6>v$vHmcjCbh zKvI!lZrs#}x()a!+5kVJ?(a|2>!$hx>WYf;sacu}7ec?nV$1+ScNxFGA1{3yz+LVv zfV6GptSSWhDA0&}2*BpJkr3FncM#xoVEBLoUd7r;$cu_Ki~&ZA!<3{A_#_^@A(!p} zZo?eTM*!b=U_;GS)GP{dek0W)H|ld5;F($vNXS}6JkpXu8lfn;Cz!l8mdm4%Rk}>d*3WV6F1L`dMaU@L@AcsA}wn&;J$NfPdG0lCr)14;+ zQnu9i&i;a_H(KgPM3HP)H1<#?rCc5{Q9Eo-VOAYcRfPhKt;63A!^#}C7CPJ`3q%@W z7}OZtv+k+a#p&i%W9J%t#y2;)_DR!v$ysEle&e^IJljh0ok=d`?wdef76RkVIb%W+ zs6=o#6S)^2sEx2ynM`X*f~5$sR2V1Ky)f5$o_Nf2TrUunGbxA1J46wP_z0k-^0*-( z4+k=+)S-#=p^4(5iK?LqNJBLMPK#vL;dtDimCj@rKLfWy+=Xu9ur%$WqkQ1wpLm9N+ja?L&V zUS1mEC{#MX+RyG`XYaDfODA0%!6xDz$U4V*T_TSw*vz3IF&-Fyj)TV}evV1txCtWO z*uFBXmHb9nPB}e$!he$ZpC%ww6BS$d;cpqu-{JE9Uu_K*R~wEXzV3;64HA6vGsB*u z%@>X-f@EvoFaa@^IQ(g|-b^f?%Y*U?_U6T#Zal)o%!$N?E!FIp1H=M3!9iS0Eiu?TyY^!XnEW| z05g0;;AQ5YZVG}j3CTr^APGf)*I->wnl6CymhznhNQH)ndCrIV&;2T38Zk;+vlemT znE==AHnI>|zzbQ*R|nKGE;n!vz*OtsM*a)g`@ay>UqRyk(gOsmc`dBU0tAi#^IL|C z^bmmnM4`xHfD!UszA=Yf1m6Hm7Nva4LSXFiZzC0eNku7qGq#8~6Ang$OXv5k^FR;K z*!%C`H4B=@IL^JzznlL7I6c?{ieQ8+I2{(8j{cPJW&Xi=Z z8#T(F|Kv0=;8=e-2meK<>jTG%C>6{lj{n@^K@afpNy5O6IXK|&XY2_c5GJfnXJHdS z^~Bd7I8eBdKqmhE9O%k7rqPD;pWI7G6<4vfQ2pO`1U2^76&xEb(!L0L-lhURenoa$ zH&0^~^u824Aj0PxdlokF-3T0urM5353~jji8jQ)qECclXC-)uF6VB!D^KYf~9q9I7 z);Z0l=KmhQHUWJ6-LnL2HviA_(X=uLH$uLiziD1?18ohV!Rai0ofdM)RviH)!6ao$hhQ&yh(;i~@u9QPcf@-z_x#Yc_xm z<$uQh0=6hyE~f1$YOO78=bXuvV1vFyCIwpoDF_Kf+4m<8@ldeW_fft#HW8q<9DCDWC_L&)hVpD_YY5 z7?O5R5Ri$KyoixZ;REHE9RHA9exTCnWcxP(%F^G;n>t8&6Z2bnLoW4(ANsNH z$$9#U>c}l&`g4m%=p`j3N7U65wh9ZAJ-sR2U7jLLSB`sr%ZML*K_x6$N+4@(q)R^& zEqpjK2|k&{bQt@VVU%WwW_z0U)4V-z0aDH>6zc&# zX3h?T`iu3p9Kw1;~8~3U27+DxzQv)&xfP-8Y-m`-ZNX)w&3R zR)1pqu)aWm0@{s_nI#ZmedFi;OMw2%V1y(Z z$Bgd`9`pFof(~0*ZDhgI_y3NDB@2mLx|)zs|4bCXs-RF4(9q|S`boP?a)XQp-nhP< zI+D!U6vz>s1&cPRbDvc9;g1{LyUOeML=jTw0%DAxpnmNgDMZ;#4#*LPCP)Bl;nH{V z>XNy@Wd?lTJY-l}J5w1}1PA#T z7K6QnoE!v-m-~=>#RXN+w9ceUFDQTG+uy7iua_0xpYd9hadYS14$)C@}+0gqK%fB;~F)w947zGAPU-}b<_72bHMqOIJey$(w}2Y{61 zc^}!*GkhAB-*{lmfwOF^CkKZM9FV~P-driQV<-$y!cn)mv3+??Q-{;yX(60RyH*^p zw*%fuLN=0!BI|DRvKr#Z%%$xX<~(4RFlo3d!y4qqtMct95CiD)Z(Mh$8U>#FzW*Jr_kVcR&Oq(h?gtFD80_5o9QWw#ANM8>RVe zya8!|=&JdjKq1haS;btI{k!dDAoJ0<*mceB_Xl%7()@#N0mLhRki7)=fK(0EjU~7( zxPt#=lz=Pz6a8h|UJ#4~kE~Z+sOeb#C(#116$0VRV$I81s678`y5iZw;0n~is^*7a z(2dQngZ+MD?=_)}P~W?C`@$RelVSn9n?DF%tbD-Z4k@M-E=maggVF+?;Gg(6D|JAO z_Oi6HegRJLN4WyHp+BizDuJ{{qdX8Zu<(_GndH#F*~}aWGiTruD>UzY|9b8^@edc^ z;6;%0EW?X>Eh0btN!s*h*~_29%RkVp{!9i64hCs3?9KSw!wYZbPr4>383&_ck>=(7 zFKAS_5FM3&zvH=n0Gx8xE_}pG`R1H*=1S|oGrzT9{4q2=LlPFTul^uv0w?&B;N`v% zc%wcni`scnH)#Dod0rry`~xY?>Ls`-{!G=;wF__HPl~2Lt6dJ3gSS}OK{r_hCV^>T z*}}*A|EGojd!_|4OCT&P%pQSw#Vveym1Cj0P++IwRw&idA>&>7eqn6&dr7fYvHiFny1gmoIWO+MqrB zCg0=_Rs;HVaprP>HX^o)aCzy&aK$1wRiE2ZqADIYQ{wZ0DfmB~({W2{o~>?ssb}V) z{Kqk+T*kOJ&UB4YehCc8o&a^YT?U7-M!GbA?$a^}UNM`9X;YWwv38Wz*Up>Spb;JH z2yqK{Fa9)V#W!GNW!zwR?DkKqOvJ2D;NK7V!N%4iC&x^L(=?+HBO;Q?>M;7@2^l72An{EDo?X^w zE(l~GKR12$?Am?5uDH{uJ_vtVH}2sLBG%3F=22$g)+vFd%=v zI-_Y$pSGq0u?*uLGV68ndGDRP@JMD-BGSm5Uf(AO3jU#tVuB|{kqZaO`a$}$((!-H zDz2!ed0-~;0YSls>*?9WdISevsPMXq*Ey`9Q0P=4B|LKiCp^?Hqy^c~ne@XGrZ&+T z$wb0gy`|%oQamGVj`uh0TP)Y7r5^^4A&*W1vx?XN;|V67J|1tEbOpzQ!5I%r5yRW7 z1;w!3w)RSLk~7~H{thF;Sa*B7@h2n#Au&e8!3}UmwE=P2NSI!<)(8p|B|<|djwmWV zJENu5R9#)IS2svNC#XY215TM=;n$oZ_n)^pPI9!ezsQYYfZvf>T#)T~4pr3Jb)yAE z11^ocVtyL%iil?B_8}Xqk{Xg)8iHxFk%%0WmIB*ZrG5UKR`B+1thihkmlhy>?P102Wn5&9-wcn-X@j62+kG-;q2$=?u%962r@wPW;2S-RRxQ#Xy5 zoB?@zp&(L~6=J`;un8at`gv_y4nSEmKZ)novKcfMFY$O^Lt`HWWPX4z5P;yqGOG+y zRUt8S#tvs?ccyxAmb!7?1_d1JMeQfFa*`q(eLbM(wO~gIZE~ zKNI?IzZ_&f0hloKE399+mXKd3$mM6<0u7Y&$r1|_1i3LO#$N=fCr-B}~opmqTxs#7*YdypEHTuEC%bQ@G3lg4Yt;B=&3O!=wYhlRUKmrx5rj{0}pl6QCMZc*SggG*c157YXQXMXX4X;5d z5@$c{P5xy_!#Vh}^+_Smb>)Eh1%wCymSj9awlLp z3Q4EL0(m8y#V9*DkaGwyh6KOpXX1ZxNKF|eyP(PAg6j*Z+RMp902B} z+~R^F;W6M5c}++R^GpWh$%3n*gw>Y_0LxPOwK-dT0nVSv)t^ohLzqta|LFEqq z>!U!iKjEGllh0XMvs+mJ_(t-qCz@q@PXdmCCBPY$>j+w%68w2e&}!X@pnw6AC1VLg zm3$agKF2js55nyfr|et-JligC-T*Ly?d`LypK(|munItb7J1jG^fm@0nM<0Iflr^E z1l;G>MZlqcpGi)T(bQ0A(lIT%@H$kk?=#;KUui@BtL?9rQXP_X_@9ILUtRMJCxOxp z2srOmN0;6JU4`fNpm0j?B8WvO3`*xKhR4v)TP7wB z7(aoFoWOU1reMXZ&2*o(;DY5=AQJWZN6+ENYe09zUON3?B1A?LyifzqwY8C$N8dhy z9hTs{>wNvSG+og81*=VmxN29IQlmV8`Op-VJfKqi6uLXG&W~OR0y*y)BGMcJW9~U$ zn%UP1_yz1U8^vMuOMJQP&EoK372IJz2H#R@tig*k>9=)2u9E=ZpMgeopN>u9uyT!D zEs-tN64W<>7=R!EQ}^K{L`@f<5BwGa&FOi7Bgn=R5TF3(#6jAgjGepW11Dzx%vF1E z>2JkP$&l920E9=t@{l0!E_@vUp`eAW(Eh%G6&D+Bmo*i zAP~+$-~{BkQCHi^4cJ@^pb!GGV|0=X6WV3#v{4_J9 zlgCPG=6L*#Bvbxsm=eQ|=6P{AjVUoMqd5g!s-GP&CxnS1ABZ7C#gGrhkl^n*2jYL+ zH}=d)h~|hs;Ee+Z8&o~)6iGgLQW~OtFf4%tN~7&jJ!IFKJZU$(I6&f|{$xk(Fo8%x z`zlApc~KY$$66mi%AxKHfX{MfnrD~YaXu&+Ml*7Dzi~s+Jdie`_1TCQSQRnm8Pqus znb3TsDI^Xm=sZ0kVu`y}TwL6vwhT{wIZsYA(4*E2o(AQ;4~|0r#(PlUcknxudv>XN zMf?-(&i=6$s_!9Lwook4)*Rd8IgsZ_s6V2t+(_)5@1FSHQ{Y>DeOiS-hMPeU^&dTC z9}qCALV(>B24nDqd@KLL(`^9em|}f7^NlH?`)vUi!5PEKs9D^rHahUJk8`xx^WPtK z3G9@E6q@J_j2l-$ZTF;no7TVILU-{U20~))yY@xx-Yft&!7HV|55AMZEOcwjwf1k% zv&}@Fb^^Pp|861JbM;P@Bhk}i9XN+Br;ei6BZQZL4|J#d1jc458})1fr~} zetsDjgwFq)0ywJ~!O&Z&c3&Rd6iR6&D7^4#sH;7 zs;Fwwy216ZZdm~NjEku*VlVt}s0WlloZ+=-*_?N7`1|PCD)jd1`FY6NB2C~Ub96Jf zr@NaYM2281ff?$kbxrr8+d)9}{40c_g;}}gNvLQ}%;gsp(_ztJ$MSkcT(3M68@sSE;R)w?$BZRoRz_MQ6c+IvPFU>Ob#v?vL+kpjUL$hapJ- zgKNl)J_GoInHMg!>n7RBHZQD&?Ea~gQ zDu_#a8<%~1;BuXYMcoPKc>so$`>I<-lYYRg)YYs__jiB$``QG-wISZLOD(+So1jz< zjF5fi20B(!L=*W)Dq=+L&kG9cE$$++k6+22^ z2)O(SL4-~Up-U7wIyR8M>D9@Qh+7^VMcEll+XdIZdgrm*2Muu4Jloo5K;csqeCsZN zX}rP`<})C`P&y63ldyxb^Clx`e9hXnba2Z@GArzzoqeBuG%xdd{q<{T_tsosjEpe( znT({cJCKMyY3TL*6*+3`%AHkC!|Y;mLMww4At?1*8TIZ$Fo@3zyeW7s3#CJc5+jsv z983ZZwupqT;T6#E{}*t332AY{$4u5Ol1_2}5r&dIHZ_%4@a~)?61Ard4c!Dn25bJy z$AbdI%RXON)D3rmlb?PrH182Y=`Ca>L~%lL`=y)h(}q_|?~FNf=8T`|ryr|8%05Xs zJDeAGxxK8wb=~oQsTwz5zHe%}T-y6k7FCdicL2<5%1rRBjQ{h8&z?YGt`>ffvAVqC zJh0B5(gqJ*Z}>0dSmT$R-0jEzoitlh`S698Y0HvjV>aulT@we-MI*B7disLL8>9*O zcklZ4aQ-ugKx%;J(u?4j?c%VOptCNfPL9h3R_o_S@Tvq^rsp1%H{&1?Jp63`jPM^D-5zW>yA>52&70f7x--Wy{w|877$R$gZg%$hd#rj#-(;*?8naxnVi$GXZrH%Wc&}UUXtjp*g@^32 zzRgixrn`t3q8LuYP)x5OHhb=@+r;_W+z@&}0YN(>*KS_C1=%rZN3H$;xucd7*!{>p znpS$UX!*GpqDKoQem;KRjN6zYm~O~$tqOaQcd*c@4C9d4(=!oqQ9Bcjwk2XYP3`S6 zclZULy*hbc+tu}wLtkB9_IiCIvRKR(Vcp}$k3XYnxR;8oU73b`b=><+dAXUJyBo8m zBs^ZR7Q2k!M%&=&xx^#6dY-BIS4>UgN8z_MVHAxdJsA1q{k6}^%ga47hhsYY)P*^l zqK->^=MTQ6j05{9hJ3aCk9|g&fMiHTC`7IOk3F#Dp;wPikXyRhPV2nWs(0ew)%z3P ztS;=GS>a8~UY5De;6g>Y3#+W0U_@4`E<+QlyDR+riuCpMcS|SUE`On6SJXc^SlTJ# zl4%4ik0&f~P2ma1@m=Z~I>hB(W6U#Rez$VF84;!~&uVIFGz>6I%T4_6vjk#|AcQ(--&8w_x_`G^X8J{rs4!gTu-9D}u+6o7%)41?-X8 zj&<{~G-wg{CXXx9(coQo(lK~rHTGFJQNA){ovuCWTsPQO(mg*~ZYj0B-Ne^#z&+2u zA@RvdxP9+(WtSf1%VuUTnx;ASk|0>LSKO|vxZ0+cp}v%QOC@ticHwAP!dDMu*xo;) z+ZT7QZ5u$ZOGp^}=K_s`>q`YeKz%&5>68Q&u|o`#kr7q(Y=88ZFK5)*U>1%&#Mu(7 z;F`?Ukgk%itEZg@i-q zUml6ceg1qpIfCD_+@(9upxeAcrBtQFB#>7W@7&U{Hnn%qZ0&BXFAp_K=SG%VSFEl7 z;<<+j0#_>caLl8{dnhh#02}M6>i*LMkL`bJcTc+`C+De`;A7&iDAqFl+1a_XK4XmNM_2b{C3w^NWULS@Ii<4}7Kxk>pN2m~B$V|>eMXVB zoGT_)ZddWp?nD4hk`WIK8#C(UKs1 z-}P4H4X_hIu~&V`_N|Lw{XVc}=`9UCzxdT_z63iRyV;>0{PXUwfzJ8R^401ndNaNX zt25n3riR_7jVCYv703x!8tB41P8H?fI2V&Ym|kS5^HlX+qb%AY<|r)SjpL}C z=D1a~K0Zt{bF#QE>fu zH1IH8~uKmO-Nlz(^P zUIBv#>~CcWjt5UVI5^u!`Hz=bV!o)o%hYkk_Au|tqP!_?2e&;55r#|jp~R%6^;9p_ z=;-!E=-hKDb|M}C5&_Wfr6w4szyxCR>A^;Y8&i8HGGM#+mU#tA%4N%4zI=HX7_HG9 zmSFYky7;u5SI28~bZov2H7Z>HbbIx3K6QuIclOa)#COU&wi=4OaQ_joPac+9oSpS1 z5;Qr4$h0tM$!xn*Q9Qw8Q z$;doZeJHBxtpldzwK+R>I;nQw?zpx_5bc(vk-?v)^dk zYQ4B!#YS7lozT*<+kbs_QO@)w_l=m*4xHtV9XpcyB8tP~I^;}?y(WMO(o^#g!+e

    X3v$^=c7-r5l&^F%gWA<4iPimpI-k$LORJO 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�&e8a!2L7gUb7qB>%@;Nh#w6P*IXl3 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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/prowler-app-social-login.md b/docs/tutorials/prowler-app-social-login.md new file mode 100644 index 0000000000..6b4dd53a57 --- /dev/null +++ b/docs/tutorials/prowler-app-social-login.md @@ -0,0 +1,52 @@ +# Social Login Configuration + +The **Prowler App** supports social login using Google and GitHub OAuth providers. This document guides you through configuring the required environment variables to enable social authentication. + +Social login buttons + +## Configuring Social Login Credentials + +To enable social login with Google and GitHub, you must define the following environment variables: + +### Google OAuth Configuration + +Set the following environment variables for Google OAuth: + +```env +SOCIAL_GOOGLE_OAUTH_CLIENT_ID="" +SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET="" +``` + +### GitHub OAuth Configuration + +Set the following environment variables for GitHub OAuth: + +```env +SOCIAL_GITHUB_OAUTH_CLIENT_ID="" +SOCIAL_GITHUB_OAUTH_CLIENT_SECRET="" +``` + +### Important Notes + +- If either `SOCIAL_GOOGLE_OAUTH_CLIENT_ID` or `SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET` is empty or not defined, the Google login button will be disabled. +- If either `SOCIAL_GITHUB_OAUTH_CLIENT_ID` or `SOCIAL_GITHUB_OAUTH_CLIENT_SECRET` is empty or not defined, the GitHub login button will be disabled. + + +Social login buttons disabled + +## Obtaining OAuth Credentials + +To obtain `CLIENT_ID` and `CLIENT_SECRET` for each provider, follow their official documentation: + +- **Google OAuth**: [Google OAuth Credentials Setup](https://developers.google.com/identity/protocols/oauth2) +- **GitHub OAuth**: [GitHub OAuth App Setup](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) + +### Steps Overview + +For both providers, the process generally involves: + +1. Registering your application in the provider's developer portal. +2. Defining the authorized redirect URL (`SOCIAL__OAUTH_CALLBACK_URL`). +3. Copying the generated `CLIENT_ID` and `CLIENT_SECRET` into the corresponding environment variables. + +Once completed, ensure your environment variables are correctly loaded in your Prowler deployment to activate social login. diff --git a/docs/tutorials/prowler-app.md b/docs/tutorials/prowler-app.md index 6228836fcf..61c92d2a15 100644 --- a/docs/tutorials/prowler-app.md +++ b/docs/tutorials/prowler-app.md @@ -9,11 +9,23 @@ You can also access to the auto-generated **Prowler API** documentation at [http If you are a [Prowler Cloud](https://cloud.prowler.com/sign-in) user you can see API docs at [https://api.prowler.com/api/v1/docs](https://api.prowler.com/api/v1/docs) ## **Step 1: Sign Up** +### **Sign up with Email** To get started, sign up using your email and password: Sign Up Button Sign Up +### **Sign up with Social Login** + +If Social Login is enabled, you can sign up using your preferred provider (e.g., Google, GitHub). + +???+ note "How Social Login Works" + - If your email is already registered, you will be logged in, and your social account will be linked. + - If your email is not registered, a new account will be created using your social account email. + +???+ note "Enable Social Login" + See [how to configure Social Login for Prowler](prowler-app-social-login.md) to enable this feature in your own deployments. + --- ## **Step 2: Log In** diff --git a/mkdocs.yml b/mkdocs.yml index a2fa253e4e..b9c6a034ee 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,26 +50,27 @@ nav: - Requirements: getting-started/requirements.md - Tutorials: - Prowler App: - - Getting Started: tutorials/prowler-app.md - - Role-Based Access Control: tutorials/prowler-app-rbac.md + - Getting Started: tutorials/prowler-app.md + - Role-Based Access Control: tutorials/prowler-app-rbac.md + - Social Login: tutorials/prowler-app-social-login.md - CLI: - - Miscellaneous: tutorials/misc.md - - Reporting: tutorials/reporting.md - - Compliance: tutorials/compliance.md - - Dashboard: tutorials/dashboard.md - - Fixer (remediations): tutorials/fixer.md - - Quick Inventory: tutorials/quick-inventory.md - - Slack Integration: tutorials/integrations.md - - Configuration File: tutorials/configuration_file.md - - Logging: tutorials/logging.md - - Mutelist: tutorials/mutelist.md - - Check Aliases: tutorials/check-aliases.md - - Custom Metadata: tutorials/custom-checks-metadata.md - - Scan Unused Services: tutorials/scan-unused-services.md - - Pentesting: tutorials/pentesting.md - - Parallel Execution: tutorials/parallel-execution.md - - Developer Guide: developer-guide/introduction.md - - Prowler Check Kreator: tutorials/prowler-check-kreator.md + - Miscellaneous: tutorials/misc.md + - Reporting: tutorials/reporting.md + - Compliance: tutorials/compliance.md + - Dashboard: tutorials/dashboard.md + - Fixer (remediations): tutorials/fixer.md + - Quick Inventory: tutorials/quick-inventory.md + - Slack Integration: tutorials/integrations.md + - Configuration File: tutorials/configuration_file.md + - Logging: tutorials/logging.md + - Mutelist: tutorials/mutelist.md + - Check Aliases: tutorials/check-aliases.md + - Custom Metadata: tutorials/custom-checks-metadata.md + - Scan Unused Services: tutorials/scan-unused-services.md + - Pentesting: tutorials/pentesting.md + - Parallel Execution: tutorials/parallel-execution.md + - Developer Guide: developer-guide/introduction.md + - Prowler Check Kreator: tutorials/prowler-check-kreator.md - AWS: - Authentication: tutorials/aws/authentication.md - Assume Role: tutorials/aws/role-assumption.md From d0736af209f2cc239c5329c1ab9a6d41c350f9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 19 Mar 2025 13:48:49 +0100 Subject: [PATCH 041/359] fix(gcp): make provider id mandatory in test_connection (#7296) --- prowler/providers/gcp/gcp_provider.py | 12 ++++++++++-- tests/providers/gcp/gcp_provider_test.py | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/prowler/providers/gcp/gcp_provider.py b/prowler/providers/gcp/gcp_provider.py index ee3a1ad4d3..3d6700a560 100644 --- a/prowler/providers/gcp/gcp_provider.py +++ b/prowler/providers/gcp/gcp_provider.py @@ -2,7 +2,6 @@ import json import os import re import sys -from typing import Optional from colorama import Fore, Style from google.auth import default, impersonated_credentials, load_credentials_from_dict @@ -426,7 +425,7 @@ class GcpProvider(Provider): credentials_file: str = None, service_account: str = None, raise_on_exception: bool = True, - provider_id: Optional[str] = None, + provider_id: str = None, client_id: str = None, client_secret: str = None, refresh_token: str = None, @@ -483,6 +482,11 @@ class GcpProvider(Provider): ... ) """ try: + if not provider_id: + logger.error("Provider ID is required.") + raise GCPInvalidProviderIdError( + file=__file__, message="Provider ID is required." + ) # Set the GCP credentials using the provided client_id, client_secret and refresh_token from ADC gcp_credentials = None if any([client_id, client_secret, refresh_token]): @@ -495,6 +499,10 @@ class GcpProvider(Provider): gcp_credentials=gcp_credentials, service_account_key=service_account_key, ) + + if not project_id: + project_id = provider_id + if provider_id and project_id != provider_id: # Logic to check if the provider ID matches the project ID GcpProvider.validate_project_id( diff --git a/tests/providers/gcp/gcp_provider_test.py b/tests/providers/gcp/gcp_provider_test.py index c82e5320a8..a0096cc7fb 100644 --- a/tests/providers/gcp/gcp_provider_test.py +++ b/tests/providers/gcp/gcp_provider_test.py @@ -810,6 +810,7 @@ class TestGCPProvider: ): with pytest.raises(Exception) as e: GcpProvider.test_connection( + provider_id="test-provider-id", client_id="test-client-id", client_secret="test-client-secret", refresh_token="test-refresh-token", @@ -817,6 +818,20 @@ class TestGCPProvider: assert e.type == GCPTestConnectionError assert "Test exception" in e.value.args[0] + def test_test_connection_with_exception_no_project_id(self): + with patch( + "prowler.providers.gcp.gcp_provider.GcpProvider.setup_session", + side_effect=GCPInvalidProviderIdError("Test exception"), + ): + with pytest.raises(GCPInvalidProviderIdError) as e: + GcpProvider.test_connection( + client_id="test-client-id", + client_secret="test-client-secret", + refresh_token="test-refresh-token", + ) + assert e.type == GCPInvalidProviderIdError + assert "[3008] Provider ID is required." in e.value.args[0] + def test_test_connection_with_exception_service_account_key(self): with patch( "prowler.providers.gcp.gcp_provider.GcpProvider.setup_session", @@ -824,6 +839,7 @@ class TestGCPProvider: ): with pytest.raises(Exception) as e: GcpProvider.test_connection( + provider_id="test-provider-id", service_account_key={"test": "key"}, ) assert e.type == GCPTestConnectionError From 06b62826b461fd0c6c9e2d27fd455c5f87b1e020 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 19 Mar 2025 21:56:52 +0545 Subject: [PATCH 042/359] chore(dependabot): disable for v3 (#7316) --- .github/dependabot.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e535e897ce..7fcf8e46d7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -94,17 +94,18 @@ updates: - "docker" - "v4" + # Dependabot Updates are temporary disabled - 2025/03/19 # v3 - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "monthly" - open-pull-requests-limit: 10 - target-branch: v3 - labels: - - "dependencies" - - "pip" - - "v3" + # - package-ecosystem: "pip" + # directory: "/" + # schedule: + # interval: "monthly" + # open-pull-requests-limit: 10 + # target-branch: v3 + # labels: + # - "dependencies" + # - "pip" + # - "v3" - package-ecosystem: "github-actions" directory: "/" From beeee80a0b6e995aa68bee1ac8f8718c096d061a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 22:14:23 +0545 Subject: [PATCH 043/359] chore(deps): bump github/codeql-action from 3.28.11 to 3.28.12 (#7321) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-codeql.yml | 4 ++-- .github/workflows/sdk-codeql.yml | 4 ++-- .github/workflows/ui-codeql.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml index 5a1a12ea13..d5d961d5cc 100644 --- a/.github/workflows/api-codeql.yml +++ b/.github/workflows/api-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/api-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index 5f1d8fd1c1..be3c4d4f71 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -54,12 +54,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/sdk-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml index d0f3603430..3bf93b31b4 100644 --- a/.github/workflows/ui-codeql.yml +++ b/.github/workflows/ui-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/ui-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: category: "/language:${{matrix.language}}" From 283127c3f43b8e7209a204efb04e3c2436631bb8 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 19 Mar 2025 22:14:41 +0545 Subject: [PATCH 044/359] chore(aws-regions): remove backport to v3 (#7319) --- .github/workflows/sdk-refresh-aws-services-regions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index 20b7439019..c4b6b9a1bf 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -56,7 +56,7 @@ jobs: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} commit-message: "feat(regions_update): Update regions for AWS services" branch: "aws-services-regions-updated-${{ github.sha }}" - labels: "status/waiting-for-revision, severity/low, provider/aws, backport-to-v3" + labels: "status/waiting-for-revision, severity/low, provider/aws" title: "chore(regions_update): Changes in regions for AWS services" body: | ### Description From 96a879d7612a1f3e139cf1e70977d8fcedea507e Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 20 Mar 2025 15:18:31 +0545 Subject: [PATCH 045/359] fix(scan_id): Read the ID from the Scan object (#7324) --- ui/components/scans/table/scan-detail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/scans/table/scan-detail.tsx b/ui/components/scans/table/scan-detail.tsx index 2db2bb20fc..f45662b9db 100644 --- a/ui/components/scans/table/scan-detail.tsx +++ b/ui/components/scans/table/scan-detail.tsx @@ -89,7 +89,7 @@ export const ScanDetail = ({ - {renderValue(taskDetails?.attributes.task_args.scan_id)} + {scanDetails.id} From 07b9e1d3a47dd0ce6ab2c722d9f397ecaef0c242 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 20 Mar 2025 15:22:00 +0545 Subject: [PATCH 046/359] chore(api): Update CHANGELOG (#7325) --- api/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index b645d2085d..36b99d3919 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -18,6 +18,8 @@ All notable changes to the **Prowler API** are documented in this file. ### Fixed - Added a handled response in case local files are missing [(#7183)](https://github.com/prowler-cloud/prowler/pull/7183). - Fixed a race condition when deleting export files after the S3 upload [(#7172)](https://github.com/prowler-cloud/prowler/pull/7172). +- Handled exception when a provider has no secret in test connection [(#7283)](https://github.com/prowler-cloud/prowler/pull/7283). + --- From bb7ce2157e81ca8ce3415f06c5498630844c71c5 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Thu, 20 Mar 2025 13:25:28 +0100 Subject: [PATCH 047/359] chore(regions_update): Changes in regions for AWS services (#7323) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index facd5ed464..7bf9c8fbb4 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -3030,6 +3030,7 @@ "aws": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", @@ -8373,6 +8374,7 @@ "qbusiness": { "regions": { "aws": [ + "eu-west-1", "us-east-1", "us-west-2" ], @@ -8731,6 +8733,7 @@ "ap-southeast-1", "ap-southeast-2", "ap-southeast-3", + "ap-southeast-7", "ca-central-1", "eu-central-1", "eu-central-2", @@ -8741,6 +8744,7 @@ "eu-west-3", "il-central-1", "me-central-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 84b273dab995e3c07ddb0dbe9916cfd3fe9782db Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 20 Mar 2025 23:34:32 +0545 Subject: [PATCH 048/359] fix(action): Use Poetry v2 (#7329) --- .github/workflows/sdk-pypi-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml index 9c707538f4..553d50a4fa 100644 --- a/.github/workflows/sdk-pypi-release.yml +++ b/.github/workflows/sdk-pypi-release.yml @@ -68,7 +68,7 @@ jobs: - name: Install dependencies run: | - pipx install poetry==1.8.5 + pipx install poetry==2.1.1 - name: Setup Python uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 From c7460bb69c9702352d0ce5c7e46e71c54bc98629 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 24 Mar 2025 09:35:47 +0100 Subject: [PATCH 049/359] chore(regions_update): Changes in regions for AWS services (#7334) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 7bf9c8fbb4..1d75afd030 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -3038,6 +3038,7 @@ "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", @@ -3413,6 +3414,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -3426,6 +3428,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -10637,6 +10640,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", "ca-central-1", "ca-west-1", "eu-central-1", From acc708bda51cdf0118179df1b28d76c901bd3696 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 24 Mar 2025 09:46:08 +0100 Subject: [PATCH 050/359] chore(regions_update): Changes in regions for AWS services (#7250) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> From e37fd05d58ceb96e572108f107dda6953309ab50 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 24 Mar 2025 09:46:26 +0100 Subject: [PATCH 051/359] chore(regions_update): Changes in regions for AWS services (#7246) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> From 87cd143967dec2d39ae8f3517311334e12df7b38 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 24 Mar 2025 09:46:57 +0100 Subject: [PATCH 052/359] chore(regions_update): Changes in regions for AWS services (#7219) Co-authored-by: MrCloudSec <38561120+MrCloudSec@users.noreply.github.com> From 4689d7a9528c680cf1cc262d6739050534c58a9b Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 24 Mar 2025 09:48:41 +0100 Subject: [PATCH 053/359] chore: upgrade Next.js to 14.2.25 to fix auth middleware vulnerability (#7339) --- ui/package-lock.json | 99 ++++++++++++++++++++++++-------------------- ui/package.json | 2 +- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 9e8848a1d0..6c22dad646 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,7 +36,7 @@ "jose": "^5.9.3", "jwt-decode": "^4.0.0", "lucide-react": "^0.471.0", - "next": "^14.2.22", + "next": "^14.2.25", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", "radix-ui": "^1.1.3", @@ -985,9 +985,10 @@ } }, "node_modules/@next/env": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.22.tgz", - "integrity": "sha512-EQ6y1QeNQglNmNIXvwP/Bb+lf7n9WtgcWvtoFsHquVLCJUuxRs+6SfZ5EK0/EqkkLex4RrDySvKgKNN7PXip7Q==" + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.25.tgz", + "integrity": "sha512-JnzQ2cExDeG7FxJwqAksZ3aqVJrHjFwZQAEJ9gQZSoEhIow7SNoKZzju/AwQ+PLIR4NY8V0rhcVozx/2izDO0w==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "14.2.23", @@ -1000,12 +1001,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.22.tgz", - "integrity": "sha512-HUaLiehovgnqY4TMBZJ3pDaOsTE1spIXeR10pWgdQVPYqDGQmHJBj3h3V6yC0uuo/RoY2GC0YBFRkOX3dI9WVQ==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.25.tgz", + "integrity": "sha512-09clWInF1YRd6le00vt750s3m7SEYNehz9C4PUcSu3bAdCTpjIV4aTYQZ25Ehrr83VR1rZeqtKUPWSI7GfuKZQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1015,12 +1017,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.22.tgz", - "integrity": "sha512-ApVDANousaAGrosWvxoGdLT0uvLBUC+srqOcpXuyfglA40cP2LBFaGmBjhgpxYk5z4xmunzqQvcIgXawTzo2uQ==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.25.tgz", + "integrity": "sha512-V+iYM/QR+aYeJl3/FWWU/7Ix4b07ovsQ5IbkwgUK29pTHmq+5UxeDr7/dphvtXEq5pLB/PucfcBNh9KZ8vWbug==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1030,12 +1033,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.22.tgz", - "integrity": "sha512-3O2J99Bk9aM+d4CGn9eEayJXHuH9QLx0BctvWyuUGtJ3/mH6lkfAPRI4FidmHMBQBB4UcvLMfNf8vF0NZT7iKw==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.25.tgz", + "integrity": "sha512-LFnV2899PJZAIEHQ4IMmZIgL0FBieh5keMnriMY1cK7ompR+JUd24xeTtKkcaw8QmxmEdhoE5Mu9dPSuDBgtTg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1045,12 +1049,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.22.tgz", - "integrity": "sha512-H/hqfRz75yy60y5Eg7DxYfbmHMjv60Dsa6IWHzpJSz4MRkZNy5eDnEW9wyts9bkxwbOVZNPHeb3NkqanP+nGPg==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.25.tgz", + "integrity": "sha512-QC5y5PPTmtqFExcKWKYgUNkHeHE/z3lUsu83di488nyP0ZzQ3Yse2G6TCxz6nNsQwgAx1BehAJTZez+UQxzLfw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1060,12 +1065,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.22.tgz", - "integrity": "sha512-LckLwlCLcGR1hlI5eiJymR8zSHPsuruuwaZ3H2uudr25+Dpzo6cRFjp/3OR5UYJt8LSwlXv9mmY4oI2QynwpqQ==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.25.tgz", + "integrity": "sha512-y6/ML4b9eQ2D/56wqatTJN5/JR8/xdObU2Fb1RBidnrr450HLCKr6IJZbPqbv7NXmje61UyxjF5kvSajvjye5w==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1075,12 +1081,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.22.tgz", - "integrity": "sha512-qGUutzmh0PoFU0fCSu0XYpOfT7ydBZgDfcETIeft46abPqP+dmePhwRGLhFKwZWxNWQCPprH26TjaTxM0Nv8mw==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.25.tgz", + "integrity": "sha512-sPX0TSXHGUOZFvv96GoBXpB3w4emMqKeMgemrSxI7A6l55VBJp/RKYLwZIB9JxSqYPApqiREaIIap+wWq0RU8w==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1090,12 +1097,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.22.tgz", - "integrity": "sha512-K6MwucMWmIvMb9GlvT0haYsfIPxfQD8yXqxwFy4uLFMeXIb2TcVYQimxkaFZv86I7sn1NOZnpOaVk5eaxThGIw==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.25.tgz", + "integrity": "sha512-ReO9S5hkA1DU2cFCsGoOEp7WJkhFzNbU/3VUF6XxNGUCQChyug6hZdYL/istQgfT/GWE6PNIg9cm784OI4ddxQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1105,12 +1113,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.22.tgz", - "integrity": "sha512-5IhDDTPEbzPR31ZzqHe90LnNe7BlJUZvC4sA1thPJV6oN5WmtWjZ0bOYfNsyZx00FJt7gggNs6SrsX0UEIcIpA==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.25.tgz", + "integrity": "sha512-DZ/gc0o9neuCDyD5IumyTGHVun2dCox5TfPQI/BJTYwpSNYM3CZDI4i6TOdjeq1JMo+Ug4kPSMuZdwsycwFbAw==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1120,12 +1129,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.22.tgz", - "integrity": "sha512-nvRaB1PyG4scn9/qNzlkwEwLzuoPH3Gjp7Q/pLuwUgOTt1oPMlnCI3A3rgkt+eZnU71emOiEv/mR201HoURPGg==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.25.tgz", + "integrity": "sha512-KSznmS6eFjQ9RJ1nEc66kJvtGIL1iZMYmGEXsZPh2YtnLtqrgdVvKXJY2ScjjoFnG6nGLyPFR0UiEvDwVah4Tw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -12226,11 +12236,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.22", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.22.tgz", - "integrity": "sha512-Ps2caobQ9hlEhscLPiPm3J3SYhfwfpMqzsoCMZGWxt9jBRK9hoBZj2A37i8joKhsyth2EuVKDVJCTF5/H4iEDw==", + "version": "14.2.25", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.25.tgz", + "integrity": "sha512-N5M7xMc4wSb4IkPvEV5X2BRRXUmhVHNyaXwEM86+voXthSZz8ZiRyQW4p9mwAoAPIm6OzuVZtn7idgEJeAJN3Q==", + "license": "MIT", "dependencies": { - "@next/env": "14.2.22", + "@next/env": "14.2.25", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -12245,15 +12256,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.22", - "@next/swc-darwin-x64": "14.2.22", - "@next/swc-linux-arm64-gnu": "14.2.22", - "@next/swc-linux-arm64-musl": "14.2.22", - "@next/swc-linux-x64-gnu": "14.2.22", - "@next/swc-linux-x64-musl": "14.2.22", - "@next/swc-win32-arm64-msvc": "14.2.22", - "@next/swc-win32-ia32-msvc": "14.2.22", - "@next/swc-win32-x64-msvc": "14.2.22" + "@next/swc-darwin-arm64": "14.2.25", + "@next/swc-darwin-x64": "14.2.25", + "@next/swc-linux-arm64-gnu": "14.2.25", + "@next/swc-linux-arm64-musl": "14.2.25", + "@next/swc-linux-x64-gnu": "14.2.25", + "@next/swc-linux-x64-musl": "14.2.25", + "@next/swc-win32-arm64-msvc": "14.2.25", + "@next/swc-win32-ia32-msvc": "14.2.25", + "@next/swc-win32-x64-msvc": "14.2.25" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/ui/package.json b/ui/package.json index 2a7f862873..4a08e910a9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -28,7 +28,7 @@ "jose": "^5.9.3", "jwt-decode": "^4.0.0", "lucide-react": "^0.471.0", - "next": "^14.2.22", + "next": "^14.2.25", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", "radix-ui": "^1.1.3", From 64c2a2217a29fc2b769c0a54d41301e195e12ffe Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 24 Mar 2025 09:59:59 +0100 Subject: [PATCH 054/359] docs: update changelog with Next.js security patch (#7339) (#7341) --- ui/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index dcd310a8d4..d9bc4ab14e 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -15,7 +15,8 @@ All notable changes to the **Prowler UI** are documented in this file. #### 🔄 Changed - Tweak styles for compliance cards. [(#7148)](https://github.com/prowler-cloud/prowler/pull/7148). - +- Upgrade Next.js to v14.2.25 to fix a middleware authorization vulnerability. [(#7339)](https://github.com/prowler-cloud/prowler/pull/7339) + --- ### [v1.4.0] (Prowler v5.4.0) From a7f612303f4f4d385791d8fd2326bece4b861adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Mon, 24 Mar 2025 10:34:43 +0100 Subject: [PATCH 055/359] feat(compliance): Add endpoint to retrieve compliance overviews metadata (#7333) --- api/CHANGELOG.md | 1 + api/src/backend/api/specs/v1.yaml | 104 ++++++++++++++++++++++++ api/src/backend/api/tests/test_views.py | 28 +++++++ api/src/backend/api/v1/serializers.py | 11 +++ api/src/backend/api/v1/views.py | 47 +++++++++++ ui/actions/compliances/compliances.ts | 41 ++++++++++ ui/app/(prowler)/compliance/page.tsx | 6 +- 7 files changed, 235 insertions(+), 3 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 36b99d3919..f0d7a24456 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. - Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167). - HTTP Security Headers [(#7289)](https://github.com/prowler-cloud/prowler/pull/7289). +- New endpoint to get the compliance overviews metadata [(#7333)](https://github.com/prowler-cloud/prowler/pull/7333). --- diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 99f2ce68b2..36f67c0e75 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -233,6 +233,42 @@ paths: schema: $ref: '#/components/schemas/ComplianceOverviewFullResponse' description: '' + /api/v1/compliance-overviews/metadata: + get: + operationId: compliance_overviews_metadata_retrieve + description: Fetch unique metadata values from a set of compliance overviews. + This is useful for dynamic filtering. + summary: Retrieve metadata values from compliance overviews + parameters: + - in: query + name: fields[compliance-overviews-metadata] + schema: + type: array + items: + type: string + enum: + - regions + description: endpoint return only specific fields in the response on a per-type + basis by including a fields[TYPE] query parameter. + explode: false + - in: query + name: filter[scan_id] + schema: + type: string + format: uuid + description: Related scan ID. + required: true + tags: + - Compliance Overview + security: + - jwtAuth: [] + responses: + '200': + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/ComplianceOverviewMetadataResponse' + description: '' /api/v1/findings: get: operationId: findings_list @@ -3674,6 +3710,7 @@ paths: - name - manage_users - manage_account + - manage_integrations - manage_providers - manage_scans - permission_state @@ -3792,6 +3829,8 @@ paths: - -manage_users - manage_account - -manage_account + - manage_integrations + - -manage_integrations - manage_providers - -manage_providers - manage_scans @@ -3867,6 +3906,7 @@ paths: - name - manage_users - manage_account + - manage_integrations - manage_providers - manage_scans - permission_state @@ -4236,6 +4276,17 @@ paths: description: |- * `scheduled` - Scheduled * `manual` - Manual + - in: query + name: include + schema: + type: array + items: + type: string + enum: + - provider + description: include query parameter to allow the client to customize which + related resources should be returned. + explode: false - name: page[number] required: false in: query @@ -4350,6 +4401,17 @@ paths: format: uuid description: A UUID string identifying this scan. required: true + - in: query + name: include + schema: + type: array + items: + type: string + enum: + - provider + description: include query parameter to allow the client to customize which + related resources should be returned. + explode: false tags: - Scan security: @@ -6105,6 +6167,40 @@ components: $ref: '#/components/schemas/ComplianceOverviewFull' required: - data + ComplianceOverviewMetadata: + type: object + required: + - type + - id + additionalProperties: false + properties: + type: + allOf: + - $ref: '#/components/schemas/ComplianceOverviewMetadataTypeEnum' + description: The [type](https://jsonapi.org/format/#document-resource-object-identification) + member is used to describe resource objects that share common attributes + and relationships. + id: {} + attributes: + type: object + properties: + regions: + type: array + items: + type: string + required: + - regions + ComplianceOverviewMetadataResponse: + type: object + properties: + data: + $ref: '#/components/schemas/ComplianceOverviewMetadata' + required: + - data + ComplianceOverviewMetadataTypeEnum: + type: string + enum: + - compliance-overviews-metadata Finding: type: object required: @@ -8398,6 +8494,8 @@ components: type: boolean manage_account: type: boolean + manage_integrations: + type: boolean manage_providers: type: boolean manage_scans: @@ -10050,6 +10148,8 @@ components: type: boolean manage_account: type: boolean + manage_integrations: + type: boolean manage_providers: type: boolean manage_scans: @@ -10179,6 +10279,8 @@ components: type: boolean manage_account: type: boolean + manage_integrations: + type: boolean manage_providers: type: boolean manage_scans: @@ -10313,6 +10415,8 @@ components: type: boolean manage_account: type: boolean + manage_integrations: + type: boolean manage_providers: type: boolean manage_scans: diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 312ed3f8fc..c11c0dec24 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -14,6 +14,7 @@ from django.urls import reverse from rest_framework import status from api.models import ( + ComplianceOverview, Integration, Invitation, Membership, @@ -4508,6 +4509,33 @@ class TestComplianceOverviewViewSet: assert len(response.json()["data"]) == 1 assert response.json()["data"][0]["id"] == str(compliance_overview1.id) + def test_compliance_overview_metadata( + self, authenticated_client, compliance_overviews_fixture + ): + response = authenticated_client.get( + reverse("complianceoverview-metadata"), + {"filter[scan_id]": str(compliance_overviews_fixture[0].scan_id)}, + ) + data = response.json() + + expected_regions = set( + ComplianceOverview.objects.all() + .values_list("region", flat=True) + .distinct("region") + ) + + assert response.status_code == status.HTTP_200_OK + assert data["data"]["type"] == "compliance-overviews-metadata" + assert data["data"]["id"] is None + assert set(data["data"]["attributes"]["regions"]) == expected_regions + + def test_compliance_overview_metadata_missing_scan_id(self, authenticated_client): + # Attempt to list compliance overviews without providing filter[scan_id] + response = authenticated_client.get(reverse("complianceoverview-metadata")) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json()["errors"][0]["source"]["pointer"] == "filter[scan_id]" + assert response.json()["errors"][0]["code"] == "required" + @pytest.mark.django_db class TestOverviewViewSet: diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 333a6474bf..8d45e495ea 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -851,6 +851,10 @@ class ScanSerializer(RLSSerializer): "url", ] + included_serializers = { + "provider": "api.v1.serializers.ProviderIncludeSerializer", + } + class ScanIncludeSerializer(RLSSerializer): trigger = serializers.ChoiceField( @@ -1897,6 +1901,13 @@ class ComplianceOverviewFullSerializer(ComplianceOverviewSerializer): return obj.requirements +class ComplianceOverviewMetadataSerializer(serializers.Serializer): + regions = serializers.ListField(child=serializers.CharField(), allow_empty=True) + + class Meta: + resource_name = "compliance-overviews-metadata" + + # Overviews diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 7801e93110..6e889d935b 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -101,6 +101,7 @@ from api.rls import Tenant from api.utils import CustomOAuth2Client, validate_invitation from api.v1.serializers import ( ComplianceOverviewFullSerializer, + ComplianceOverviewMetadataSerializer, ComplianceOverviewSerializer, FindingDynamicFilterSerializer, FindingMetadataSerializer, @@ -2054,6 +2055,21 @@ class RoleProviderGroupRelationshipView(RelationshipView, BaseRLSViewSet): description="Fetch detailed information about a specific compliance overview by its ID, including detailed " "requirement information and check's status.", ), + metadata=extend_schema( + tags=["Compliance Overview"], + summary="Retrieve metadata values from compliance overviews", + description="Fetch unique metadata values from a set of compliance overviews. This is useful for dynamic " + "filtering.", + parameters=[ + OpenApiParameter( + name="filter[scan_id]", + required=True, + type=OpenApiTypes.UUID, + location=OpenApiParameter.QUERY, + description="Related scan ID.", + ), + ], + ), ) @method_decorator(CACHE_DECORATOR, name="list") @method_decorator(CACHE_DECORATOR, name="retrieve") @@ -2115,6 +2131,8 @@ class ComplianceOverviewViewSet(BaseRLSViewSet): def get_serializer_class(self): if self.action == "retrieve": return ComplianceOverviewFullSerializer + elif self.action == "metadata": + return ComplianceOverviewMetadataSerializer return super().get_serializer_class() def list(self, request, *args, **kwargs): @@ -2131,6 +2149,35 @@ class ComplianceOverviewViewSet(BaseRLSViewSet): ) return super().list(request, *args, **kwargs) + @action(detail=False, methods=["get"], url_name="metadata") + def metadata(self, request): + scan_id = request.query_params.get("filter[scan_id]") + if not scan_id: + raise ValidationError( + [ + { + "detail": "This query parameter is required.", + "status": 400, + "source": {"pointer": "filter[scan_id]"}, + "code": "required", + } + ] + ) + + tenant_id = self.request.tenant_id + + regions = list( + ComplianceOverview.objects.filter(tenant_id=tenant_id, scan_id=scan_id) + .values_list("region", flat=True) + .order_by("region") + .distinct() + ) + result = {"regions": regions} + + serializer = self.get_serializer(data=result) + serializer.is_valid(raise_exception=True) + return Response(serializer.data, status=status.HTTP_200_OK) + @extend_schema(tags=["Overview"]) @extend_schema_view( diff --git a/ui/actions/compliances/compliances.ts b/ui/actions/compliances/compliances.ts index a89c932d91..77b7e76696 100644 --- a/ui/actions/compliances/compliances.ts +++ b/ui/actions/compliances/compliances.ts @@ -43,3 +43,44 @@ export const getCompliancesOverview = async ({ return undefined; } }; + +export const getComplianceOverviewMetadataInfo = async ({ + query = "", + sort = "", + filters = {}, +}) => { + const session = await auth(); + + const url = new URL(`${apiBaseUrl}/compliance-overviews/metadata`); + + if (query) url.searchParams.append("filter[search]", query); + if (sort) url.searchParams.append("sort", sort); + + Object.entries(filters).forEach(([key, value]) => { + // Define filters to exclude + if (key !== "filter[search]") { + url.searchParams.append(key, String(value)); + } + }); + + try { + const response = await fetch(url.toString(), { + headers: { + Accept: "application/vnd.api+json", + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch compliance overview metadata info: ${response.statusText}`); + } + + const parsedData = parseStringify(await response.json()); + + return parsedData; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching compliance overview metadata info:", error); + return undefined; + } +}; diff --git a/ui/app/(prowler)/compliance/page.tsx b/ui/app/(prowler)/compliance/page.tsx index 68789e6900..3c1ff0cd0a 100644 --- a/ui/app/(prowler)/compliance/page.tsx +++ b/ui/app/(prowler)/compliance/page.tsx @@ -4,7 +4,7 @@ import { Spacer } from "@nextui-org/react"; import { Suspense } from "react"; import { getCompliancesOverview } from "@/actions/compliances"; -import { getMetadataInfo } from "@/actions/findings"; +import { getComplianceOverviewMetadataInfo } from "@/actions/compliances"; import { getProvider } from "@/actions/providers"; import { getScans } from "@/actions/scans"; import { @@ -70,10 +70,10 @@ export default async function Compliance({ searchParams.scanId || expandedScansData[0]?.id || null; const query = (filters["filter[search]"] as string) || ""; - const metadataInfoData = await getMetadataInfo({ + const metadataInfoData = await getComplianceOverviewMetadataInfo({ query, filters: { - "filter[scan]": selectedScanId, + "filter[scan_id]": selectedScanId, }, }); From 9923def4cb16fab510dd9a9d46d6e52bf2ab5267 Mon Sep 17 00:00:00 2001 From: Jonny <106528116+jonathanbro@users.noreply.github.com> Date: Mon, 24 Mar 2025 10:21:01 +0000 Subject: [PATCH 056/359] chore(awslambda): update obsolete lambda runtimes (#7330) Co-authored-by: MrCloudSec --- prowler/config/config.yaml | 2 ++ .../awslambda_function_using_supported_runtimes.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index 2f3f63478d..2462578daa 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -95,6 +95,7 @@ aws: "python3.6", "python2.7", "python3.7", + "python3.8", "nodejs4.3", "nodejs4.3-edge", "nodejs6.10", @@ -105,6 +106,7 @@ aws: "nodejs14.x", "nodejs16.x", "dotnet5.0", + "dotnet6", "dotnet7", "dotnetcore1.0", "dotnetcore2.0", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py index 8845f1e54d..8fc74ea50a 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py +++ b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py @@ -8,6 +8,7 @@ default_obsolete_lambda_runtimes = [ "python3.6", "python2.7", "python3.7", + "python3.8", "nodejs4.3", "nodejs4.3-edge", "nodejs6.10", @@ -18,6 +19,7 @@ default_obsolete_lambda_runtimes = [ "nodejs14.x", "nodejs16.x", "dotnet5.0", + "dotnet6", "dotnet7", "dotnetcore1.0", "dotnetcore2.0", From 307315000814b91c1dc3c3594d7a18279bef89c1 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 24 Mar 2025 16:17:18 +0545 Subject: [PATCH 057/359] chore(next): Remove `x-powered-by` header (#7346) --- ui/next.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/next.config.js b/ui/next.config.js index 059659b2f0..2f71bd229c 100644 --- a/ui/next.config.js +++ b/ui/next.config.js @@ -14,6 +14,7 @@ const cspHeader = ` ` module.exports = { + poweredByHeader: false, output: "standalone", async headers() { return [ From 7a1e611b8828c0ec19a5dd60655f60e026dac57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Mon, 24 Mar 2025 14:39:14 +0100 Subject: [PATCH 058/359] ref(providers): Refactor provider deletion functions (#7349) --- api/CHANGELOG.md | 7 +++ api/src/backend/api/db_utils.py | 33 ++++++++---- api/src/backend/api/signals.py | 7 ++- api/src/backend/api/tests/test_db_utils.py | 5 +- api/src/backend/api/v1/views.py | 2 + api/src/backend/config/celery.py | 4 +- api/src/backend/tasks/jobs/deletion.py | 56 ++++++++++---------- api/src/backend/tasks/tasks.py | 12 +++-- api/src/backend/tasks/tests/test_deletion.py | 8 +-- 9 files changed, 80 insertions(+), 54 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index f0d7a24456..4fe334b562 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -14,6 +14,13 @@ All notable changes to the **Prowler API** are documented in this file. --- +## [v1.5.2] (Prowler v5.4.2) + +### Changed +- Refactored deletion logic and implemented retry mechanism for deletion tasks [(#7349)](https://github.com/prowler-cloud/prowler/pull/7349). + +--- + ## [v1.5.1] (Prowler v5.4.1) ### Fixed diff --git a/api/src/backend/api/db_utils.py b/api/src/backend/api/db_utils.py index a7dfee863f..f36c2ef05c 100644 --- a/api/src/backend/api/db_utils.py +++ b/api/src/backend/api/db_utils.py @@ -6,6 +6,7 @@ from datetime import datetime, timedelta, timezone from django.conf import settings from django.contrib.auth.models import BaseUserManager from django.db import connection, models, transaction +from django_celery_beat.models import PeriodicTask from psycopg2 import connect as psycopg2_connect from psycopg2.extensions import AsIs, new_type, register_adapter, register_type from rest_framework_json_api.serializers import ValidationError @@ -105,11 +106,12 @@ def generate_random_token(length: int = 14, symbols: str | None = None) -> str: return "".join(secrets.choice(symbols or _symbols) for _ in range(length)) -def batch_delete(queryset, batch_size=5000): +def batch_delete(tenant_id, queryset, batch_size=5000): """ Deletes objects in batches and returns the total number of deletions and a summary. Args: + tenant_id (str): Tenant ID the queryset belongs to. queryset (QuerySet): The queryset of objects to delete. batch_size (int): The number of objects to delete in each batch. @@ -120,15 +122,16 @@ def batch_delete(queryset, batch_size=5000): deletion_summary = {} while True: - # Get a batch of IDs to delete - batch_ids = set( - queryset.values_list("id", flat=True).order_by("id")[:batch_size] - ) - if not batch_ids: - # No more objects to delete - break + with rls_transaction(tenant_id, POSTGRES_TENANT_VAR): + # Get a batch of IDs to delete + batch_ids = set( + queryset.values_list("id", flat=True).order_by("id")[:batch_size] + ) + if not batch_ids: + # No more objects to delete + break - deleted_count, deleted_info = queryset.filter(id__in=batch_ids).delete() + deleted_count, deleted_info = queryset.filter(id__in=batch_ids).delete() total_deleted += deleted_count for model_label, count in deleted_info.items(): @@ -137,6 +140,18 @@ def batch_delete(queryset, batch_size=5000): return total_deleted, deletion_summary +def delete_related_daily_task(provider_id: str): + """ + Deletes the periodic task associated with a specific provider. + + Args: + provider_id (str): The unique identifier for the provider + whose related periodic task should be deleted. + """ + task_name = f"scan-perform-scheduled-{provider_id}" + PeriodicTask.objects.filter(name=task_name).delete() + + # Postgres Enums diff --git a/api/src/backend/api/signals.py b/api/src/backend/api/signals.py index 44c2e0b4fd..d9dc0a72d9 100644 --- a/api/src/backend/api/signals.py +++ b/api/src/backend/api/signals.py @@ -1,12 +1,12 @@ from celery import states from celery.signals import before_task_publish +from config.celery import celery_app from django.db.models.signals import post_delete from django.dispatch import receiver -from django_celery_beat.models import PeriodicTask from django_celery_results.backends.database import DatabaseBackend +from api.db_utils import delete_related_daily_task from api.models import Provider -from config.celery import celery_app def create_task_result_on_publish(sender=None, headers=None, **kwargs): # noqa: F841 @@ -31,5 +31,4 @@ before_task_publish.connect( @receiver(post_delete, sender=Provider) def delete_provider_scan_task(sender, instance, **kwargs): # noqa: F841 # Delete the associated periodic task when the provider is deleted - task_name = f"scan-perform-scheduled-{instance.id}" - PeriodicTask.objects.filter(name=task_name).delete() + delete_related_daily_task(instance.id) diff --git a/api/src/backend/api/tests/test_db_utils.py b/api/src/backend/api/tests/test_db_utils.py index 6c2364600a..e22b1417bc 100644 --- a/api/src/backend/api/tests/test_db_utils.py +++ b/api/src/backend/api/tests/test_db_utils.py @@ -131,9 +131,10 @@ class TestBatchDelete: return provider_count @pytest.mark.django_db - def test_batch_delete(self, create_test_providers): + def test_batch_delete(self, tenants_fixture, create_test_providers): + tenant_id = str(tenants_fixture[0].id) _, summary = batch_delete( - Provider.objects.all(), batch_size=create_test_providers // 2 + tenant_id, Provider.objects.all(), batch_size=create_test_providers // 2 ) assert Provider.objects.all().count() == 0 assert summary == {"api.Provider": create_test_providers} diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 6e889d935b..8fd5254ba5 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -55,6 +55,7 @@ from tasks.tasks import ( from api.base_views import BaseRLSViewSet, BaseTenantViewset, BaseUserViewset from api.db_router import MainRouter +from api.db_utils import delete_related_daily_task from api.filters import ( ComplianceOverviewFilter, FindingFilter, @@ -1088,6 +1089,7 @@ class ProviderViewSet(BaseRLSViewSet): provider = get_object_or_404(Provider, pk=pk) provider.is_deleted = True provider.save() + delete_related_daily_task(str(provider.id)) with transaction.atomic(): task = delete_provider_task.delay( diff --git a/api/src/backend/config/celery.py b/api/src/backend/config/celery.py index 4486a0bf97..4c667b7bc5 100644 --- a/api/src/backend/config/celery.py +++ b/api/src/backend/config/celery.py @@ -50,9 +50,9 @@ class RLSTask(Task): tenant_id = kwargs.get("tenant_id") with rls_transaction(tenant_id): - APITask.objects.create( + APITask.objects.update_or_create( id=task_result_instance.task_id, tenant_id=tenant_id, - task_runner_task=task_result_instance, + defaults={"task_runner_task": task_result_instance}, ) return result diff --git a/api/src/backend/tasks/jobs/deletion.py b/api/src/backend/tasks/jobs/deletion.py index 5ca08e70bb..d72b8de40e 100644 --- a/api/src/backend/tasks/jobs/deletion.py +++ b/api/src/backend/tasks/jobs/deletion.py @@ -1,5 +1,5 @@ from celery.utils.log import get_task_logger -from django.db import transaction +from django.db import DatabaseError from api.db_router import MainRouter from api.db_utils import batch_delete, rls_transaction @@ -8,11 +8,12 @@ from api.models import Finding, Provider, Resource, Scan, ScanSummary, Tenant logger = get_task_logger(__name__) -def delete_provider(pk: str): +def delete_provider(tenant_id: str, pk: str): """ Gracefully deletes an instance of a provider along with its related data. Args: + tenant_id (str): Tenant ID the resources belong to. pk (str): The primary key of the Provider instance to delete. Returns: @@ -22,33 +23,31 @@ def delete_provider(pk: str): Raises: Provider.DoesNotExist: If no instance with the provided primary key exists. """ - instance = Provider.all_objects.get(pk=pk) - deletion_summary = {} + with rls_transaction(tenant_id): + instance = Provider.all_objects.get(pk=pk) + deletion_summary = {} + deletion_steps = [ + ("Scan Summaries", ScanSummary.all_objects.filter(scan__provider=instance)), + ("Findings", Finding.all_objects.filter(scan__provider=instance)), + ("Resources", Resource.all_objects.filter(provider=instance)), + ("Scans", Scan.all_objects.filter(provider=instance)), + ] - with transaction.atomic(): - # Delete Scan Summaries - scan_summaries_qs = ScanSummary.all_objects.filter(scan__provider=instance) - _, scans_summ_summary = batch_delete(scan_summaries_qs) - deletion_summary.update(scans_summ_summary) + for step_name, queryset in deletion_steps: + try: + _, step_summary = batch_delete(tenant_id, queryset) + deletion_summary.update(step_summary) + except DatabaseError as db_error: + logger.error(f"Error deleting {step_name}: {db_error}") + raise - # Delete Findings - findings_qs = Finding.all_objects.filter(scan__provider=instance) - _, findings_summary = batch_delete(findings_qs) - deletion_summary.update(findings_summary) - - # Delete Resources - resources_qs = Resource.all_objects.filter(provider=instance) - _, resources_summary = batch_delete(resources_qs) - deletion_summary.update(resources_summary) - - # Delete Scans - scans_qs = Scan.all_objects.filter(provider=instance) - _, scans_summary = batch_delete(scans_qs) - deletion_summary.update(scans_summary) - - provider_deleted_count, provider_summary = instance.delete() + try: + with rls_transaction(tenant_id): + _, provider_summary = instance.delete() deletion_summary.update(provider_summary) - + except DatabaseError as db_error: + logger.error(f"Error deleting Provider: {db_error}") + raise return deletion_summary @@ -66,9 +65,8 @@ def delete_tenant(pk: str): deletion_summary = {} for provider in Provider.objects.using(MainRouter.admin_db).filter(tenant_id=pk): - with rls_transaction(pk): - summary = delete_provider(provider.id) - deletion_summary.update(summary) + summary = delete_provider(pk, provider.id) + deletion_summary.update(summary) Tenant.objects.using(MainRouter.admin_db).filter(id=pk).delete() diff --git a/api/src/backend/tasks/tasks.py b/api/src/backend/tasks/tasks.py index 05c1919f17..c9b8d1ab2a 100644 --- a/api/src/backend/tasks/tasks.py +++ b/api/src/backend/tasks/tasks.py @@ -43,9 +43,10 @@ def check_provider_connection_task(provider_id: str): return check_provider_connection(provider_id=provider_id) -@shared_task(base=RLSTask, name="provider-deletion", queue="deletion") -@set_tenant -def delete_provider_task(provider_id: str): +@shared_task( + base=RLSTask, name="provider-deletion", queue="deletion", autoretry_for=(Exception,) +) +def delete_provider_task(provider_id: str, tenant_id: str): """ Task to delete a specific Provider instance. @@ -53,6 +54,7 @@ def delete_provider_task(provider_id: str): Args: provider_id (str): The primary key of the `Provider` instance to be deleted. + tenant_id (str): Tenant ID the provider belongs to. Returns: tuple: A tuple containing: @@ -60,7 +62,7 @@ def delete_provider_task(provider_id: str): - A dictionary with the count of deleted instances per model, including related models if cascading deletes were triggered. """ - return delete_provider(pk=provider_id) + return delete_provider(tenant_id=tenant_id, pk=provider_id) @shared_task(base=RLSTask, name="scan-perform", queue="scans") @@ -174,7 +176,7 @@ def perform_scan_summary_task(tenant_id: str, scan_id: str): return aggregate_findings(tenant_id=tenant_id, scan_id=scan_id) -@shared_task(name="tenant-deletion", queue="deletion") +@shared_task(name="tenant-deletion", queue="deletion", autoretry_for=(Exception,)) def delete_tenant_task(tenant_id: str): return delete_tenant(pk=tenant_id) diff --git a/api/src/backend/tasks/tests/test_deletion.py b/api/src/backend/tasks/tests/test_deletion.py index 00d218e192..81cdb44daa 100644 --- a/api/src/backend/tasks/tests/test_deletion.py +++ b/api/src/backend/tasks/tests/test_deletion.py @@ -9,17 +9,19 @@ from api.models import Provider, Tenant class TestDeleteProvider: def test_delete_provider_success(self, providers_fixture): instance = providers_fixture[0] - result = delete_provider(instance.id) + tenant_id = str(instance.tenant_id) + result = delete_provider(tenant_id, instance.id) assert result with pytest.raises(ObjectDoesNotExist): Provider.objects.get(pk=instance.id) - def test_delete_provider_does_not_exist(self): + def test_delete_provider_does_not_exist(self, tenants_fixture): + tenant_id = str(tenants_fixture[0].id) non_existent_pk = "babf6796-cfcc-4fd3-9dcf-88d012247645" with pytest.raises(ObjectDoesNotExist): - delete_provider(non_existent_pk) + delete_provider(tenant_id, non_existent_pk) @pytest.mark.django_db From 24784f2ce5062cfb53ac1bd9e4571a97252c0d03 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 24 Mar 2025 15:22:36 +0100 Subject: [PATCH 059/359] feat(scans): add download button column for completed scans in table (#7353) --- ui/components/icons/Icons.tsx | 31 ++++++++- .../scans/table/scans/column-get-scans.tsx | 64 +++++++++++++++++-- .../table/scans/data-table-row-actions.tsx | 43 ++----------- ui/components/scans/trigger-icon.tsx | 25 ++++++++ ui/components/ui/entities/date-with-time.tsx | 2 +- ui/lib/helper.ts | 38 +++++++++++ 6 files changed, 156 insertions(+), 47 deletions(-) create mode 100644 ui/components/scans/trigger-icon.tsx diff --git a/ui/components/icons/Icons.tsx b/ui/components/icons/Icons.tsx index b2ebc70fd2..4cf36bc6c7 100644 --- a/ui/components/icons/Icons.tsx +++ b/ui/components/icons/Icons.tsx @@ -760,7 +760,7 @@ export const AddIcon: React.FC = ({ }; export const ScheduleIcon: React.FC = ({ - size, + size = 24, height, width, ...props @@ -768,8 +768,9 @@ export const ScheduleIcon: React.FC = ({ return ( = ({ ); +export const ManualIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => ( + +); + export const SpinnerIcon: React.FC = ({ size = 24, width, diff --git a/ui/components/scans/table/scans/column-get-scans.tsx b/ui/components/scans/table/scans/column-get-scans.tsx index 6fbbcdcc3e..b81ffd6287 100644 --- a/ui/components/scans/table/scans/column-get-scans.tsx +++ b/ui/components/scans/table/scans/column-get-scans.tsx @@ -1,15 +1,21 @@ "use client"; +import { Tooltip } from "@nextui-org/react"; import { ColumnDef } from "@tanstack/react-table"; +import { DownloadIcon } from "lucide-react"; import { useSearchParams } from "next/navigation"; import { InfoIcon } from "@/components/icons"; +import { toast } from "@/components/ui"; +import { CustomButton } from "@/components/ui/custom"; import { DateWithTime, EntityInfoShort } from "@/components/ui/entities"; import { TriggerSheet } from "@/components/ui/sheet"; import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table"; +import { downloadScanZip } from "@/lib/helper"; import { ScanProps } from "@/types"; import { LinkToFindingsFromScan } from "../../link-to-findings-from-scan"; +import { TriggerIcon } from "../../trigger-icon"; import { DataTableRowActions } from "./data-table-row-actions"; import { DataTableRowDetails } from "./data-table-row-details"; @@ -104,6 +110,43 @@ export const ColumnGetScans: ColumnDef[] = [ return ; }, }, + { + id: "download", + header: () => ( +

    +

    Download

    + +
    + +
    +
    +
    + ), + cell: ({ row }) => { + const scanId = row.original.id; + const scanState = row.original.attributes?.state; + + return ( +
    + downloadScanZip(scanId, toast)} + className="p-0 text-default-500 hover:text-primary disabled:opacity-30" + isIconOnly + ariaLabel="Download .zip" + size="sm" + > + + +
    + ); + }, + }, + // { // accessorKey: "scanner_args", // header: "Scanner Args", @@ -121,7 +164,11 @@ export const ColumnGetScans: ColumnDef[] = [ const { attributes: { unique_resource_count }, } = getScanData(row); - return

    {unique_resource_count}

    ; + return ( +
    + {unique_resource_count} +
    + ); }, }, { @@ -163,7 +210,11 @@ export const ColumnGetScans: ColumnDef[] = [ const { attributes: { trigger }, } = getScanData(row); - return

    {trigger}

    ; + return ( +
    + +
    + ); }, }, { @@ -179,8 +230,13 @@ export const ColumnGetScans: ColumnDef[] = [ if (!name || name.length === 0) { return -; } - - return {name}; + return ( +
    + + {name === "Daily scheduled scan" ? "scheduled scan" : name} + +
    + ); }, }, { diff --git a/ui/components/scans/table/scans/data-table-row-actions.tsx b/ui/components/scans/table/scans/data-table-row-actions.tsx index 46c1111bd3..ad61a174e8 100644 --- a/ui/components/scans/table/scans/data-table-row-actions.tsx +++ b/ui/components/scans/table/scans/data-table-row-actions.tsx @@ -16,10 +16,10 @@ import { Row } from "@tanstack/react-table"; import { DownloadIcon } from "lucide-react"; import { useState } from "react"; -import { getExportsZip } from "@/actions/scans"; import { VerticalDotsIcon } from "@/components/icons"; import { useToast } from "@/components/ui"; import { CustomAlertModal } from "@/components/ui/custom"; +import { downloadScanZip } from "@/lib/helper"; import { EditScanForm } from "../../forms"; @@ -38,41 +38,6 @@ export function DataTableRowActions({ const scanName = (row.original as any).attributes?.name; const scanState = (row.original as any).attributes?.state; - const handleExportZip = async () => { - const result = await getExportsZip(scanId); - - if (result?.success && result?.data) { - // Convert base64 to blob - const binaryString = window.atob(result.data); - const bytes = new Uint8Array(binaryString.length); - for (let i = 0; i < binaryString.length; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - const blob = new Blob([bytes], { type: "application/zip" }); - - // Create download link - const url = window.URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = result.filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - - toast({ - title: "Download Complete", - description: "Your scan report has been downloaded successfully.", - }); - } else if (result?.error) { - toast({ - variant: "destructive", - title: "Download Failed", - description: result.error, - }); - } - }; - return ( <> ({ color="default" variant="flat" > - + } - onPress={handleExportZip} + onPress={() => downloadScanZip(scanId, toast)} isDisabled={scanState !== "completed"} > Download .zip diff --git a/ui/components/scans/trigger-icon.tsx b/ui/components/scans/trigger-icon.tsx new file mode 100644 index 0000000000..4176a1e5da --- /dev/null +++ b/ui/components/scans/trigger-icon.tsx @@ -0,0 +1,25 @@ +import { Tooltip } from "@nextui-org/react"; + +import { ManualIcon, ScheduleIcon } from "@/components/icons"; + +interface TriggerIconProps { + trigger: "scheduled" | "manual"; + iconSize?: number; +} + +export function TriggerIcon({ trigger, iconSize = 24 }: TriggerIconProps) { + return ( + +
    + {trigger === "scheduled" ? ( + + ) : ( + + )} +
    +
    + ); +} diff --git a/ui/components/ui/entities/date-with-time.tsx b/ui/components/ui/entities/date-with-time.tsx index 17600762c1..50e0efe8b5 100644 --- a/ui/components/ui/entities/date-with-time.tsx +++ b/ui/components/ui/entities/date-with-time.tsx @@ -32,7 +32,7 @@ export const DateWithTime: React.FC = ({ > {formattedDate} {showTime && ( - {formattedTime} + {formattedTime} )}
diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index b0eaef6221..3e70760d8d 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -1,4 +1,6 @@ +import { getExportsZip } from "@/actions/scans"; import { getTask } from "@/actions/task"; +import { useToast } from "@/components/ui"; import { AuthSocialProvider, MetaDataProps, PermissionInfo } from "@/types"; export const baseUrl = process.env.AUTH_URL || "http://localhost:3000"; @@ -37,6 +39,42 @@ export const getAuthUrl = (provider: AuthSocialProvider) => { return url.toString(); }; +export const downloadScanZip = async ( + scanId: string, + toast: ReturnType["toast"], +) => { + const result = await getExportsZip(scanId); + + if (result?.success && result?.data) { + const binaryString = window.atob(result.data); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + const blob = new Blob([bytes], { type: "application/zip" }); + + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = result.filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + + toast({ + title: "Download Complete", + description: "Your scan report has been downloaded successfully.", + }); + } else if (result?.error) { + toast({ + variant: "destructive", + title: "Download Failed", + description: result.error, + }); + } +}; + export const isGoogleOAuthEnabled = !!process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_ID && !!process.env.SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET; From 0a9d0688a75a223bba7dc10bb6718940e37d4eab Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 24 Mar 2025 15:28:13 +0100 Subject: [PATCH 060/359] =?UTF-8?q?docs(changelog):=20document=20addition?= =?UTF-8?q?=20of=20download=20column=20in=20scans=20table=20=E2=80=A6=20(#?= =?UTF-8?q?7354)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index d9bc4ab14e..f87a0bb72c 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to the **Prowler UI** are documented in this file. - Social login integration with Google and GitHub [(#7218)](https://github.com/prowler-cloud/prowler/pull/7218) - Added `one-time scan` feature: Adds support for single scan execution. [(#7188)](https://github.com/prowler-cloud/prowler/pull/7188) - Accepted invitations can no longer be edited. [(#7198)](https://github.com/prowler-cloud/prowler/pull/7198) +- Added download column in scans table to download reports for completed scans. [(#7353)](https://github.com/prowler-cloud/prowler/pull/7353) + #### 🔄 Changed From ce33dbf8233b903410a01d9114035407303b89b1 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 24 Mar 2025 15:38:09 +0100 Subject: [PATCH 061/359] chore(findings): apply default filter to show failed findings (#7356) --- ui/components/scans/link-to-findings-from-scan.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/scans/link-to-findings-from-scan.tsx b/ui/components/scans/link-to-findings-from-scan.tsx index e20996c54b..41a5eff38a 100644 --- a/ui/components/scans/link-to-findings-from-scan.tsx +++ b/ui/components/scans/link-to-findings-from-scan.tsx @@ -9,7 +9,7 @@ interface LinkToFindingsProps { export const LinkToFindingsFromScan = ({ scanId }: LinkToFindingsProps) => { return ( Date: Mon, 24 Mar 2025 15:41:35 +0100 Subject: [PATCH 062/359] docs: update readme (#7357) --- ui/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index f87a0bb72c..583ef7d78a 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Tweak styles for compliance cards. [(#7148)](https://github.com/prowler-cloud/prowler/pull/7148). - Upgrade Next.js to v14.2.25 to fix a middleware authorization vulnerability. [(#7339)](https://github.com/prowler-cloud/prowler/pull/7339) +- Apply default filter to show only failed items when coming from scan table. [(#7356)](https://github.com/prowler-cloud/prowler/pull/7356) --- From bf475234a5285dacec980b1e0e2e0d2ed2ac551b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Mon, 24 Mar 2025 17:39:47 +0100 Subject: [PATCH 063/359] build(api): Force django-allauth==65.4.1 (#7358) --- api/poetry.lock | 2 +- api/pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/poetry.lock b/api/poetry.lock index 02bc2aaef4..0e9af82b8c 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -5428,4 +5428,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.13" -content-hash = "5892eb6b702f29a7eebff3f9dc899ea8d78cac622aa8f299ef4c662df8f5b51d" +content-hash = "0da43d42c9cdb0b990cfd184ba776e3ce2a5ee72fbd076e980d7111c772d6000" diff --git a/api/pyproject.toml b/api/pyproject.toml index c5e151aab6..d8e74d6260 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -8,6 +8,7 @@ dependencies = [ "celery[pytest] (>=5.4.0,<6.0.0)", "dj-rest-auth[with_social,jwt] (==7.0.1)", "django==5.1.7", + "django-allauth==65.4.1", "django-celery-beat (>=2.7.0,<3.0.0)", "django-celery-results (>=2.5.1,<3.0.0)", "django-cors-headers==4.4.0", From f52d005e2d92a0e1b1d536a273d875509b72a9a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:42:50 +0545 Subject: [PATCH 064/359] chore(deps): bump tj-actions/changed-files from 46.0.1 to 46.0.3 (#7363) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-pull-request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 312bcd68a3..9c0fd9f667 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -75,7 +75,7 @@ jobs: - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 + uses: tj-actions/changed-files@823fcebdb31bb35fdf2229d9f769b400309430d0 # v46.0.3 with: files: api/** files_ignore: | diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 5fee5003bf..b637c32f0b 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -25,7 +25,7 @@ jobs: - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1 + uses: tj-actions/changed-files@823fcebdb31bb35fdf2229d9f769b400309430d0 # v46.0.3 with: files: ./** files_ignore: | From d6862766d379fc59420c37e538522b4089f83457 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:43:02 +0545 Subject: [PATCH 065/359] chore(deps): bump github/codeql-action from 3.28.12 to 3.28.13 (#7367) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-codeql.yml | 4 ++-- .github/workflows/sdk-codeql.yml | 4 ++-- .github/workflows/ui-codeql.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml index d5d961d5cc..eac9e55c2b 100644 --- a/.github/workflows/api-codeql.yml +++ b/.github/workflows/api-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/api-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index be3c4d4f71..b68dd5d405 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -54,12 +54,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/sdk-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml index 3bf93b31b4..fd623c3619 100644 --- a/.github/workflows/ui-codeql.yml +++ b/.github/workflows/ui-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/ui-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: category: "/language:${{matrix.language}}" From dd05ef79746e3fdd86a02d3445e2d89591232e75 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 25 Mar 2025 08:45:37 +0100 Subject: [PATCH 066/359] chore(scans): properly enable link to findings when scan is completed (#7368) --- ui/CHANGELOG.md | 2 +- ui/components/scans/link-to-findings-from-scan.tsx | 12 +++++++++--- ui/components/scans/table/scans/column-get-scans.tsx | 8 +++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 583ef7d78a..4500c57bd4 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -13,12 +13,12 @@ All notable changes to the **Prowler UI** are documented in this file. - Accepted invitations can no longer be edited. [(#7198)](https://github.com/prowler-cloud/prowler/pull/7198) - Added download column in scans table to download reports for completed scans. [(#7353)](https://github.com/prowler-cloud/prowler/pull/7353) - #### 🔄 Changed - Tweak styles for compliance cards. [(#7148)](https://github.com/prowler-cloud/prowler/pull/7148). - Upgrade Next.js to v14.2.25 to fix a middleware authorization vulnerability. [(#7339)](https://github.com/prowler-cloud/prowler/pull/7339) - Apply default filter to show only failed items when coming from scan table. [(#7356)](https://github.com/prowler-cloud/prowler/pull/7356) +- Fix link behavior in scan cards: only disable "View Findings" when scan is not completed or executing. [(#7368)](https://github.com/prowler-cloud/prowler/pull/7368) --- diff --git a/ui/components/scans/link-to-findings-from-scan.tsx b/ui/components/scans/link-to-findings-from-scan.tsx index 41a5eff38a..07bc16ecd1 100644 --- a/ui/components/scans/link-to-findings-from-scan.tsx +++ b/ui/components/scans/link-to-findings-from-scan.tsx @@ -4,16 +4,22 @@ import { CustomButton } from "@/components/ui/custom"; interface LinkToFindingsProps { scanId?: string; + isDisabled?: boolean; } -export const LinkToFindingsFromScan = ({ scanId }: LinkToFindingsProps) => { +export const LinkToFindingsFromScan = ({ + scanId, + isDisabled, +}: LinkToFindingsProps) => { return ( See Findings diff --git a/ui/components/scans/table/scans/column-get-scans.tsx b/ui/components/scans/table/scans/column-get-scans.tsx index b81ffd6287..c931cde668 100644 --- a/ui/components/scans/table/scans/column-get-scans.tsx +++ b/ui/components/scans/table/scans/column-get-scans.tsx @@ -107,7 +107,13 @@ export const ColumnGetScans: ColumnDef[] = [ header: "Findings", cell: ({ row }) => { const { id } = getScanData(row); - return ; + const scanState = row.original.attributes?.state; + return ( + + ); }, }, { From 332b98a1ab34f53a55c9bd13834ebf18be6af7e5 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:22:35 +0100 Subject: [PATCH 067/359] fix(iam): handle `UnboundLocalError` cannot access local variable 'report' (#7361) --- ...ermissions_to_administer_resource_locks.py | 2 +- ...sions_to_administer_resource_locks_test.py | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py b/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py index d3df749b20..2abbf40510 100644 --- a/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py +++ b/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py @@ -29,5 +29,5 @@ class iam_custom_role_has_permissions_to_administer_resource_locks(Check): report.status_extended = f"Role {custom_role.name} from subscription {subscription} has permission to administer resource locks." exits_role_with_permission_over_locks = True break - findings.append(report) + findings.append(report) return findings diff --git a/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py b/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py index 90c838317d..760015e6a1 100644 --- a/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py +++ b/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py @@ -198,3 +198,25 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: result[0].resource_id == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id ) + + def test_iam_custom_roles_empty_list_but_with_key(self): + defender_client = mock.MagicMock + defender_client.custom_roles = {AZURE_SUBSCRIPTION_ID: []} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.iam.iam_custom_role_has_permissions_to_administer_resource_locks.iam_custom_role_has_permissions_to_administer_resource_locks.iam_client", + new=defender_client, + ), + ): + from prowler.providers.azure.services.iam.iam_custom_role_has_permissions_to_administer_resource_locks.iam_custom_role_has_permissions_to_administer_resource_locks import ( + iam_custom_role_has_permissions_to_administer_resource_locks, + ) + + check = iam_custom_role_has_permissions_to_administer_resource_locks() + result = check.execute() + assert len(result) == 0 From e68aa62f94222439d0d242dccf1c1d50907573fd Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 25 Mar 2025 09:24:32 +0100 Subject: [PATCH 068/359] fix(iam): handle none SAML Providers (#7359) --- .../iam_check_saml_providers_sts.py | 38 +++++++++++-------- .../iam_check_saml_providers_sts_test.py | 25 ++++++++++++ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/prowler/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py b/prowler/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py index 7d9cc26a90..3cf2e70a6c 100644 --- a/prowler/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py +++ b/prowler/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py @@ -5,22 +5,28 @@ from prowler.providers.aws.services.iam.iam_client import iam_client class iam_check_saml_providers_sts(Check): def execute(self) -> Check_Report_AWS: findings = [] - if not iam_client.saml_providers and iam_client.saml_providers is not None: - report = Check_Report_AWS( - metadata=self.metadata(), resource=iam_client.saml_providers - ) - report.resource_id = iam_client.audited_account - report.resource_arn = iam_client.audited_account_arn - report.region = iam_client.region - report.status = "FAIL" - report.status_extended = "No SAML Providers found." - findings.append(report) + if iam_client.saml_providers is not None: + if not iam_client.saml_providers: + report = Check_Report_AWS( + metadata=self.metadata(), resource=iam_client.saml_providers + ) + report.resource_id = iam_client.audited_account + report.resource_arn = iam_client.audited_account_arn + report.region = iam_client.region + report.status = "FAIL" + report.status_extended = "No SAML Providers found." + findings.append(report) - for provider in iam_client.saml_providers.values(): - report = Check_Report_AWS(metadata=self.metadata(), resource=provider) - report.region = iam_client.region - report.status = "PASS" - report.status_extended = f"SAML Provider {provider.name} has been found." - findings.append(report) + else: + for provider in iam_client.saml_providers.values(): + report = Check_Report_AWS( + metadata=self.metadata(), resource=provider + ) + report.region = iam_client.region + report.status = "PASS" + report.status_extended = ( + f"SAML Provider {provider.name} has been found." + ) + findings.append(report) return findings diff --git a/tests/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py b/tests/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py index 87fb82808b..3bf7c3fcbf 100644 --- a/tests/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py +++ b/tests/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py @@ -123,3 +123,28 @@ nTTxU4a7x1naFxzYXK1iQ1vMARKMjDb19QEJIEJKZlDK4uS7yMlf1nFS assert result[0].resource_arn == "arn:aws:iam::123456789012:root" assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].status_extended == "No SAML Providers found." + + @mock_aws + def test_iam_check_saml_providers_sts_none_saml_providers(self): + from prowler.providers.aws.services.iam.iam_service import IAM + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.iam.iam_check_saml_providers_sts.iam_check_saml_providers_sts.iam_client", + new=IAM(aws_provider), + ) as iam_client: + # Test Check + from prowler.providers.aws.services.iam.iam_check_saml_providers_sts.iam_check_saml_providers_sts import ( + iam_check_saml_providers_sts, + ) + + iam_client.saml_providers = None + + check = iam_check_saml_providers_sts() + result = check.execute() + assert len(result) == 0 From 1e324b7ed2407bd9ab0eb40765518f7cbd06d659 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:28:37 +0100 Subject: [PATCH 069/359] fix(network): handle `Nonetype is not iterable` for security groups (#7208) --- ...network_http_internet_access_restricted.py | 5 +- .../network_rdp_internet_access_restricted.py | 5 +- .../azure/services/network/network_service.py | 12 ++-- .../network_ssh_internet_access_restricted.py | 5 +- .../network_udp_internet_access_restricted.py | 14 +++-- ...rk_http_internet_access_restricted_test.py | 12 +++- ...ork_rdp_internet_access_restricted_test.py | 55 +++++++++++++++++++ ...ork_ssh_internet_access_restricted_test.py | 55 +++++++++++++++++++ ...ork_udp_internet_access_restricted_test.py | 55 +++++++++++++++++++ 9 files changed, 203 insertions(+), 15 deletions(-) diff --git a/prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.py b/prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.py index 5fd8d053f4..61f018bae4 100644 --- a/prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.py +++ b/prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.py @@ -17,7 +17,10 @@ class network_http_internet_access_restricted(Check): ( rule.destination_port_range == "80" or ( - "-" in rule.destination_port_range + ( + rule.destination_port_range + and "-" in rule.destination_port_range + ) and int(rule.destination_port_range.split("-")[0]) <= 80 and int(rule.destination_port_range.split("-")[1]) >= 80 ) diff --git a/prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.py b/prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.py index 8c3d804ccd..7d08678d27 100644 --- a/prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.py +++ b/prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.py @@ -17,7 +17,10 @@ class network_rdp_internet_access_restricted(Check): ( rule.destination_port_range == "3389" or ( - "-" in rule.destination_port_range + ( + rule.destination_port_range + and "-" in rule.destination_port_range + ) and int(rule.destination_port_range.split("-")[0]) <= 3389 and int(rule.destination_port_range.split("-")[1]) >= 3389 ) diff --git a/prowler/providers/azure/services/network/network_service.py b/prowler/providers/azure/services/network/network_service.py index 6842926014..fb9af1af3a 100644 --- a/prowler/providers/azure/services/network/network_service.py +++ b/prowler/providers/azure/services/network/network_service.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List +from typing import List, Optional from azure.mgmt.network import NetworkManagementClient @@ -168,11 +168,11 @@ class NetworkWatcher: class SecurityRule: id: str name: str - destination_port_range: str - protocol: str - source_address_prefix: str - access: str - direction: str + destination_port_range: Optional[str] + protocol: Optional[str] + source_address_prefix: Optional[str] + access: Optional[str] + direction: Optional[str] @dataclass diff --git a/prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.py b/prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.py index a24cd10da3..e4207194e1 100644 --- a/prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.py +++ b/prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.py @@ -17,7 +17,10 @@ class network_ssh_internet_access_restricted(Check): ( rule.destination_port_range == "22" or ( - "-" in rule.destination_port_range + ( + rule.destination_port_range + and "-" in rule.destination_port_range + ) and int(rule.destination_port_range.split("-")[0]) <= 22 and int(rule.destination_port_range.split("-")[1]) >= 22 ) diff --git a/prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.py b/prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.py index c465c891f2..ebd5fc7d50 100644 --- a/prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.py +++ b/prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.py @@ -14,10 +14,16 @@ class network_udp_internet_access_restricted(Check): report.status = "PASS" report.status_extended = f"Security Group {security_group.name} from subscription {subscription} has UDP internet access restricted." rule_fail_condition = any( - rule.protocol in ["UDP", "Udp"] - and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"] - and rule.access == "Allow" - and rule.direction == "Inbound" + ( + rule.protocol in ["UDP", "Udp"] + and ( + rule.source_address_prefix + and rule.source_address_prefix + in ["Internet", "*", "0.0.0.0/0"] + ) + and rule.access == "Allow" + and rule.direction == "Inbound" + ) for rule in security_group.security_rules ) if rule_fail_condition: diff --git a/tests/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted_test.py b/tests/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted_test.py index 31cd18c2a3..9b8959777e 100644 --- a/tests/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted_test.py +++ b/tests/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted_test.py @@ -37,7 +37,7 @@ class Test_network_http_internet_access_restricted: result = check.execute() assert len(result) == 0 - def test_network_security_groups_no_security_rules(self): + def test_network_security_groups_none_destination_port_range(self): network_client = mock.MagicMock security_group_name = "Security Group Name" security_group_id = str(uuid4()) @@ -48,7 +48,15 @@ class Test_network_http_internet_access_restricted: id=security_group_id, name=security_group_name, location="location", - security_rules=[], + security_rules=[ + SecurityRule( + destination_port_range=None, + protocol="TCP", + source_address_prefix="Internet", + access="Allow", + direction="Inbound", + ) + ], ) ] } diff --git a/tests/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted_test.py b/tests/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted_test.py index f1410e1c7c..9f8c9b145a 100644 --- a/tests/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted_test.py +++ b/tests/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted_test.py @@ -37,6 +37,61 @@ class Test_network_rdp_internet_access_restricted: result = check.execute() assert len(result) == 0 + def test_network_security_groups_none_destination_port_range(self): + network_client = mock.MagicMock + security_group_name = "Security Group Name" + security_group_id = str(uuid4()) + + network_client.security_groups = { + AZURE_SUBSCRIPTION_ID: [ + SecurityGroup( + id=security_group_id, + name=security_group_name, + location="location", + security_rules=[ + SecurityRule( + destination_port_range=None, + protocol="TCP", + source_address_prefix="Internet", + access="Allow", + direction="Inbound", + ) + ], + ) + ] + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.network.network_service.Network", + new=network_client, + ) as service_client, + mock.patch( + "prowler.providers.azure.services.network.network_client.network_client", + new=service_client, + ), + ): + from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import ( + network_http_internet_access_restricted, + ) + + check = network_http_internet_access_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION_ID} has HTTP internet access restricted." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION_ID + assert result[0].resource_name == security_group_name + assert result[0].resource_id == security_group_id + assert result[0].location == "location" + def test_network_security_groups_no_security_rules(self): network_client = mock.MagicMock security_group_name = "Security Group Name" diff --git a/tests/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted_test.py b/tests/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted_test.py index be567f6ae3..4472055075 100644 --- a/tests/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted_test.py +++ b/tests/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted_test.py @@ -37,6 +37,61 @@ class Test_network_ssh_internet_access_restricted: result = check.execute() assert len(result) == 0 + def test_network_security_groups_none_destination_port_range(self): + network_client = mock.MagicMock + security_group_name = "Security Group Name" + security_group_id = str(uuid4()) + + network_client.security_groups = { + AZURE_SUBSCRIPTION_ID: [ + SecurityGroup( + id=security_group_id, + name=security_group_name, + location="location", + security_rules=[ + SecurityRule( + destination_port_range=None, + protocol="TCP", + source_address_prefix="Internet", + access="Allow", + direction="Inbound", + ) + ], + ) + ] + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.network.network_service.Network", + new=network_client, + ) as service_client, + mock.patch( + "prowler.providers.azure.services.network.network_client.network_client", + new=service_client, + ), + ): + from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import ( + network_http_internet_access_restricted, + ) + + check = network_http_internet_access_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION_ID} has HTTP internet access restricted." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION_ID + assert result[0].resource_name == security_group_name + assert result[0].resource_id == security_group_id + assert result[0].location == "location" + def test_network_security_groups_no_security_rules(self): network_client = mock.MagicMock security_group_name = "Security Group Name" diff --git a/tests/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted_test.py b/tests/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted_test.py index eea305e77b..7d519df326 100644 --- a/tests/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted_test.py +++ b/tests/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted_test.py @@ -37,6 +37,61 @@ class Test_network_udp_internet_access_restricted: result = check.execute() assert len(result) == 0 + def test_network_security_groups_none_source_address_prefix(self): + network_client = mock.MagicMock + security_group_name = "Security Group Name" + security_group_id = str(uuid4()) + + network_client.security_groups = { + AZURE_SUBSCRIPTION_ID: [ + SecurityGroup( + id=security_group_id, + name=security_group_name, + location="location", + security_rules=[ + SecurityRule( + destination_port_range=None, + protocol="TCP", + source_address_prefix=None, + access="Allow", + direction="Inbound", + ) + ], + ) + ] + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.network.network_service.Network", + new=network_client, + ) as service_client, + mock.patch( + "prowler.providers.azure.services.network.network_client.network_client", + new=service_client, + ), + ): + from prowler.providers.azure.services.network.network_http_internet_access_restricted.network_http_internet_access_restricted import ( + network_http_internet_access_restricted, + ) + + check = network_http_internet_access_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Security Group {security_group_name} from subscription {AZURE_SUBSCRIPTION_ID} has HTTP internet access restricted." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION_ID + assert result[0].resource_name == security_group_name + assert result[0].resource_id == security_group_id + assert result[0].location == "location" + def test_network_security_groups_no_security_rules(self): network_client = mock.MagicMock security_group_name = "Security Group Name" From d989425490545432274fab6fd50b8c2879bd8319 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:33:00 +0100 Subject: [PATCH 070/359] fix(vm): handle NoneType accessing security_profile (#7221) --- .../providers/azure/services/vm/vm_service.py | 4 +- .../vm_trusted_launch_enabled.py | 3 +- .../vm_trusted_launch_enabled_test.py | 49 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/prowler/providers/azure/services/vm/vm_service.py b/prowler/providers/azure/services/vm/vm_service.py index 4700f81eca..2ef3c9e30a 100644 --- a/prowler/providers/azure/services/vm/vm_service.py +++ b/prowler/providers/azure/services/vm/vm_service.py @@ -50,7 +50,7 @@ class VirtualMachines(AzureService): else None ), location=vm.location, - security_profile=vm.security_profile, + security_profile=getattr(vm, "security_profile", None), extensions=[ VirtualMachineExtension(id=extension.id) for extension in getattr(vm, "resources", []) @@ -142,7 +142,7 @@ class VirtualMachine: resource_id: str resource_name: str location: str - security_profile: SecurityProfile + security_profile: Optional[SecurityProfile] extensions: list[VirtualMachineExtension] storage_profile: Optional[StorageProfile] = None diff --git a/prowler/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled.py b/prowler/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled.py index e4a4d9d082..d4896b70ec 100644 --- a/prowler/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled.py +++ b/prowler/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled.py @@ -14,7 +14,8 @@ class vm_trusted_launch_enabled(Check): report.status_extended = f"VM {vm.resource_name} has trusted launch disabled in subscription {subscription_name}" if ( - vm.security_profile.security_type == "TrustedLaunch" + vm.security_profile + and vm.security_profile.security_type == "TrustedLaunch" and vm.security_profile.uefi_settings.secure_boot_enabled and vm.security_profile.uefi_settings.v_tpm_enabled ): diff --git a/tests/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled_test.py b/tests/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled_test.py index 8f81756561..05e96a5c1d 100644 --- a/tests/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled_test.py +++ b/tests/providers/azure/services/vm/vm_trusted_launch_enabled/vm_trusted_launch_enabled_test.py @@ -158,3 +158,52 @@ class Test_vm_trusted_launch_enabled: result[0].status_extended == f"VM VMTest has trusted launch disabled in subscription {AZURE_SUBSCRIPTION_ID}" ) + + def test_vm_no_security_profile(self): + vm_id = str(uuid4()) + vm_client = mock.MagicMock + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client", + new=vm_client, + ), + ): + from prowler.providers.azure.services.vm.vm_service import VirtualMachine + from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import ( + vm_trusted_launch_enabled, + ) + + vm_client.virtual_machines = { + AZURE_SUBSCRIPTION_ID: { + vm_id: VirtualMachine( + resource_id=vm_id, + resource_name="VMTest", + location="location", + security_profile=None, + extensions=[], + storage_profile=mock.MagicMock( + os_disk=mock.MagicMock( + create_option="FromImage", + managed_disk=mock.MagicMock(id="managed_disk_id"), + ), + data_disks=[], + ), + ) + } + } + + check = vm_trusted_launch_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].subscription == AZURE_SUBSCRIPTION_ID + assert result[0].resource_name == "VMTest" + assert result[0].resource_id == vm_id + assert ( + result[0].status_extended + == f"VM VMTest has trusted launch disabled in subscription {AZURE_SUBSCRIPTION_ID}" + ) From 76a8e2be1f2d44908ed4659cfd2e545b017d39bf Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 25 Mar 2025 09:52:36 +0100 Subject: [PATCH 071/359] chore: tweak for button see findings (#7369) --- ui/components/scans/link-to-findings-from-scan.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/components/scans/link-to-findings-from-scan.tsx b/ui/components/scans/link-to-findings-from-scan.tsx index 07bc16ecd1..6f94773cee 100644 --- a/ui/components/scans/link-to-findings-from-scan.tsx +++ b/ui/components/scans/link-to-findings-from-scan.tsx @@ -17,7 +17,6 @@ export const LinkToFindingsFromScan = ({ ariaLabel="Go to Findings page" variant="ghost" className="text-xs font-medium text-default-500 hover:text-primary disabled:opacity-30" - // color="action" size="sm" isDisabled={isDisabled} > From 52e5cc23e42c0175cbb7d8004300f08bee5887a4 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:35:37 +0100 Subject: [PATCH 072/359] fix(storagegateway): describe smb/nfs share per region (#7374) --- .../services/storagegateway/storagegateway_service.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/prowler/providers/aws/services/storagegateway/storagegateway_service.py b/prowler/providers/aws/services/storagegateway/storagegateway_service.py index b375b87282..b55c5c7f4d 100644 --- a/prowler/providers/aws/services/storagegateway/storagegateway_service.py +++ b/prowler/providers/aws/services/storagegateway/storagegateway_service.py @@ -51,7 +51,10 @@ class StorageGateway(AWSService): logger.info("StorageGateway - Describe NFS FileShares...") try: for fileshare in self.fileshares: - if fileshare.fs_type == "NFS": + if ( + fileshare.region == regional_client.region + and fileshare.fs_type == "NFS" + ): response = regional_client.describe_nfs_file_shares( FileShareARNList=[fileshare.arn] ) @@ -70,7 +73,10 @@ class StorageGateway(AWSService): logger.info("StorageGateway - Describe SMB FileShares...") try: for fileshare in self.fileshares: - if fileshare.fs_type == "SMB": + if ( + fileshare.region == regional_client.region + and fileshare.fs_type == "SMB" + ): response = regional_client.describe_smb_file_shares( FileShareARNList=[fileshare.arn] ) From dd1cc2d025ec7494d97ef9f09cbcf6757eeb9d86 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 25 Mar 2025 11:39:19 +0100 Subject: [PATCH 073/359] fix(s3): handle None S3 account public access block (#7350) --- .../s3_account_level_public_access_blocks.py | 45 ++++++++++--------- .../providers/aws/services/s3/s3_service.py | 7 +-- ...account_level_public_access_blocks_test.py | 30 +++++++++++++ 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.py b/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.py index 5e027c1510..bbb123fdfb 100644 --- a/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.py +++ b/prowler/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks.py @@ -6,27 +6,28 @@ from prowler.providers.aws.services.s3.s3control_client import s3control_client class s3_account_level_public_access_blocks(Check): def execute(self): findings = [] - report = Check_Report_AWS( - metadata=self.metadata(), - resource=s3control_client.account_public_access_block, - ) - if ( - s3control_client.account_public_access_block - and s3control_client.account_public_access_block.ignore_public_acls - and s3control_client.account_public_access_block.restrict_public_buckets - ): - report.status = "PASS" - report.status_extended = f"Block Public Access is configured for the account {s3control_client.audited_account}." - report.region = s3control_client.region - report.resource_id = s3control_client.audited_account - report.resource_arn = s3_client.account_arn_template - findings.append(report) - elif s3_client.buckets or s3_client.provider.scan_unused_services: - report.status = "FAIL" - report.status_extended = f"Block Public Access is not configured for the account {s3control_client.audited_account}." - report.region = s3control_client.region - report.resource_id = s3control_client.audited_account - report.resource_arn = s3_client.account_arn_template - findings.append(report) + if s3control_client.account_public_access_block is not None: + report = Check_Report_AWS( + metadata=self.metadata(), + resource=s3control_client.account_public_access_block, + ) + if ( + s3control_client.account_public_access_block + and s3control_client.account_public_access_block.ignore_public_acls + and s3control_client.account_public_access_block.restrict_public_buckets + ): + report.status = "PASS" + report.status_extended = f"Block Public Access is configured for the account {s3control_client.audited_account}." + report.region = s3control_client.region + report.resource_id = s3control_client.audited_account + report.resource_arn = s3_client.account_arn_template + findings.append(report) + elif s3_client.buckets or s3_client.provider.scan_unused_services: + report.status = "FAIL" + report.status_extended = f"Block Public Access is not configured for the account {s3control_client.audited_account}." + report.region = s3control_client.region + report.resource_id = s3control_client.audited_account + report.resource_arn = s3_client.account_arn_template + findings.append(report) return findings diff --git a/prowler/providers/aws/services/s3/s3_service.py b/prowler/providers/aws/services/s3/s3_service.py index 3894e1001d..c8f7c0343d 100644 --- a/prowler/providers/aws/services/s3/s3_service.py +++ b/prowler/providers/aws/services/s3/s3_service.py @@ -511,9 +511,10 @@ class S3Control(AWSService): def __init__(self, provider): # Call AWSService's __init__ super().__init__(__class__.__name__, provider) - self.account_public_access_block = self._get_public_access_block() + self.account_public_access_block = None self.access_points = {} self.multi_region_access_points = {} + self._get_public_access_block() self.__threading_call__(self._list_access_points) self.__threading_call__(self._get_access_point, self.access_points.values()) if self.audited_partition == "aws": @@ -525,7 +526,7 @@ class S3Control(AWSService): public_access_block = self.client.get_public_access_block( AccountId=self.audited_account )["PublicAccessBlockConfiguration"] - return PublicAccessBlock( + self.account_public_access_block = PublicAccessBlock( block_public_acls=public_access_block["BlockPublicAcls"], ignore_public_acls=public_access_block["IgnorePublicAcls"], block_public_policy=public_access_block["BlockPublicPolicy"], @@ -534,7 +535,7 @@ class S3Control(AWSService): except Exception as error: if "NoSuchPublicAccessBlockConfiguration" in str(error): # Set all block as False - return PublicAccessBlock( + self.account_public_access_block = PublicAccessBlock( block_public_acls=False, ignore_public_acls=False, block_public_policy=False, diff --git a/tests/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks_test.py b/tests/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks_test.py index 994a6bcbe6..96b02bd88b 100644 --- a/tests/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks_test.py +++ b/tests/providers/aws/services/s3/s3_account_level_public_access_blocks/s3_account_level_public_access_blocks_test.py @@ -156,3 +156,33 @@ class Test_s3_account_level_public_access_blocks: result = check.execute() assert len(result) == 0 + + def test_none_bucket_account_public_block(self): + from prowler.providers.aws.services.s3.s3_service import S3, S3Control + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), + mock.patch( + "prowler.providers.aws.services.s3.s3_account_level_public_access_blocks.s3_account_level_public_access_blocks.s3_client", + new=S3(aws_provider), + ), + mock.patch( + "prowler.providers.aws.services.s3.s3_account_level_public_access_blocks.s3_account_level_public_access_blocks.s3control_client", + new=S3Control(aws_provider), + ) as s3control_client, + ): + # Test Check + from prowler.providers.aws.services.s3.s3_account_level_public_access_blocks.s3_account_level_public_access_blocks import ( + s3_account_level_public_access_blocks, + ) + + s3control_client.account_public_access_block = None + check = s3_account_level_public_access_blocks() + result = check.execute() + + assert len(result) == 0 From 5d6ed640f082172acbd6b29bb74228f010d765f9 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:25:15 +0100 Subject: [PATCH 074/359] fix(vm): handle `Nonetype is not iterable` for extensions (#7360) Co-authored-by: Sergio Garcia --- .../providers/azure/services/vm/vm_service.py | 59 ++++++++++++------- .../azure/services/vm/vm_service_test.py | 45 ++++++++++++++ 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/prowler/providers/azure/services/vm/vm_service.py b/prowler/providers/azure/services/vm/vm_service.py index 2ef3c9e30a..d5d0dde5c7 100644 --- a/prowler/providers/azure/services/vm/vm_service.py +++ b/prowler/providers/azure/services/vm/vm_service.py @@ -24,6 +24,33 @@ class VirtualMachines(AzureService): virtual_machines.update({subscription_name: {}}) for vm in virtual_machines_list: + storage_profile = getattr(vm, "storage_profile", None) + os_disk = ( + getattr(storage_profile, "os_disk", None) + if storage_profile + else None + ) + + data_disks = [] + if storage_profile and getattr(storage_profile, "data_disks", []): + data_disks = [ + DataDisk( + lun=data_disk.lun, + name=data_disk.name, + managed_disk=data_disk.managed_disk, + ) + for data_disk in getattr(storage_profile, "data_disks", []) + if data_disk + ] + + extensions = [] + if getattr(vm, "resources", []): + extensions = [ + VirtualMachineExtension(id=extension.id) + for extension in getattr(vm, "resources", []) + if extension + ] + virtual_machines[subscription_name].update( { vm.id: VirtualMachine( @@ -32,29 +59,19 @@ class VirtualMachines(AzureService): storage_profile=( StorageProfile( os_disk=OSDisk( - name=vm.storage_profile.os_disk.name, - managed_disk=vm.storage_profile.os_disk.managed_disk, + name=getattr(os_disk, "name", None), + managed_disk=getattr( + os_disk, "managed_disk", None + ), ), - data_disks=[ - DataDisk( - lun=data_disk.lun, - name=data_disk.name, - managed_disk=data_disk.managed_disk, - ) - for data_disk in getattr( - vm.storage_profile, "data_disks", [] - ) - ], + data_disks=data_disks, ) - if getattr(vm, "storage_profile", None) + if storage_profile else None ), location=vm.location, security_profile=getattr(vm, "security_profile", None), - extensions=[ - VirtualMachineExtension(id=extension.id) - for extension in getattr(vm, "resources", []) - ], + extensions=extensions, ) } ) @@ -110,13 +127,13 @@ class UefiSettings: @dataclass class SecurityProfile: security_type: str - uefi_settings: UefiSettings + uefi_settings: Optional[UefiSettings] @dataclass class OSDisk: - name: str - managed_disk: bool + name: Optional[str] + managed_disk: Optional[bool] @dataclass @@ -128,7 +145,7 @@ class DataDisk: @dataclass class StorageProfile: - os_disk: OSDisk + os_disk: Optional[OSDisk] data_disks: List[DataDisk] diff --git a/tests/providers/azure/services/vm/vm_service_test.py b/tests/providers/azure/services/vm/vm_service_test.py index 5bd225e1bf..6e0f53e2e5 100644 --- a/tests/providers/azure/services/vm/vm_service_test.py +++ b/tests/providers/azure/services/vm/vm_service_test.py @@ -41,6 +41,32 @@ def mock_vm_get_virtual_machines(_): } +def mock_vm_get_virtual_machines_with_none(_): + return { + AZURE_SUBSCRIPTION_ID: { + "vm_id-1": VirtualMachine( + resource_id="/subscriptions/resource_id", + resource_name="VMWithNoneValues", + location="location", + security_profile=None, + extensions=None, + storage_profile=None, + ), + "vm_id-2": VirtualMachine( + resource_id="/subscriptions/resource_id2", + resource_name="VMWithPartialNone", + location="location", + security_profile=None, + extensions=None, + storage_profile=StorageProfile( + os_disk=None, + data_disks=None, + ), + ), + } + } + + def mock_vm_get_disks(_): return { AZURE_SUBSCRIPTION_ID: { @@ -137,3 +163,22 @@ class Test_VirtualMachines_Service: disks[AZURE_SUBSCRIPTION_ID]["disk_id-1"].encryption_type == "EncryptionAtRestWithPlatformKey" ) + + +@patch( + "prowler.providers.azure.services.vm.vm_service.VirtualMachines._get_virtual_machines", + new=mock_vm_get_virtual_machines_with_none, +) +class Test_VirtualMachines_NoneCases: + def test_virtual_machine_with_none_storage_profile(self): + virtual_machines = VirtualMachines(set_mocked_azure_provider()) + vm_1 = virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID]["vm_id-1"] + assert vm_1.storage_profile is None + assert vm_1.resource_name == "VMWithNoneValues" + + def test_virtual_machine_with_partial_none_storage_profile(self): + virtual_machines = VirtualMachines(set_mocked_azure_provider()) + vm_2 = virtual_machines.virtual_machines[AZURE_SUBSCRIPTION_ID]["vm_id-2"] + assert vm_2.storage_profile.os_disk is None + assert vm_2.storage_profile.data_disks is None + assert vm_2.resource_name == "VMWithPartialNone" From bcc0b59de192965b1d8769b296c65c5f8e0bf6ff Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Wed, 26 Mar 2025 12:52:35 +0100 Subject: [PATCH 075/359] chore(regions_update): Changes in regions for AWS services (#7382) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 1d75afd030..25609b133b 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -2888,9 +2888,7 @@ }, "cur": { "regions": { - "aws": [ - "us-east-1" - ], + "aws": [], "aws-cn": [ "cn-northwest-1" ], @@ -6123,6 +6121,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -6136,6 +6135,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 5ea910625954c98c21ab697751c00071d5d34164 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 26 Mar 2025 19:25:00 +0100 Subject: [PATCH 076/359] fix(fms): resource metadata could not be converted to dict (#7379) --- .../fms/fms_policy_compliant/fms_policy_compliant.py | 4 +--- .../fms/fms_policy_compliant/fms_policy_compliant_test.py | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/prowler/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant.py b/prowler/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant.py index a36cd9f8e0..ebe1660aff 100644 --- a/prowler/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant.py +++ b/prowler/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant.py @@ -6,9 +6,7 @@ class fms_policy_compliant(Check): def execute(self): findings = [] if fms_client.fms_admin_account: - report = Check_Report_AWS( - metadata=self.metadata(), resource=fms_client.fms_policies - ) + report = Check_Report_AWS(metadata=self.metadata(), resource={}) report.region = fms_client.region report.resource_arn = fms_client.policy_arn_template report.resource_id = fms_client.audited_account diff --git a/tests/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant_test.py b/tests/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant_test.py index 0c6fa8606a..4810d6c1e6 100644 --- a/tests/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant_test.py +++ b/tests/providers/aws/services/fms/fms_policy_compliant/fms_policy_compliant_test.py @@ -97,6 +97,7 @@ class Test_fms_policy_compliant: == f"arn:aws:fms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:policy" ) assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource == fms_client.fms_policies[0] def test_fms_admin_with_compliant_policies(self): fms_client = mock.MagicMock @@ -150,6 +151,7 @@ class Test_fms_policy_compliant: == f"arn:aws:fms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:policy" ) assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource == {} def test_fms_admin_with_non_and_compliant_policies(self): fms_client = mock.MagicMock @@ -209,6 +211,7 @@ class Test_fms_policy_compliant: == f"arn:aws:fms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:policy" ) assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource == fms_client.fms_policies[0] def test_fms_admin_without_policies(self): fms_client = mock.MagicMock @@ -246,6 +249,7 @@ class Test_fms_policy_compliant: == f"arn:aws:fms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:policy" ) assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource == {} def test_fms_admin_with_policy_with_null_status(self): fms_client = mock.MagicMock @@ -297,3 +301,4 @@ class Test_fms_policy_compliant: assert result[0].resource_id == "12345678901" assert result[0].resource_arn == "arn:aws:fms:us-east-1:12345678901" assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource == fms_client.fms_policies[0] From d39598c9fc8f53ad4454c155a198fa2137e49a3d Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 26 Mar 2025 19:39:27 +0100 Subject: [PATCH 077/359] fix(stepfunctions): `Nonetype` object has no attribute `level` (#7386) --- ...tepfunctions_statemachine_logging_enabled.py | 5 ++++- ...nctions_statemachine_logging_enabled_test.py | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled.py b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled.py index f5dc00e121..328896c8e6 100644 --- a/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled.py +++ b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled.py @@ -33,7 +33,10 @@ class stepfunctions_statemachine_logging_enabled(Check): report.status = "PASS" report.status_extended = f"Step Functions state machine {state_machine.name} has logging enabled." - if state_machine.logging_configuration.level == LoggingLevel.OFF: + if ( + not state_machine.logging_configuration + or state_machine.logging_configuration.level == LoggingLevel.OFF + ): report.status = "FAIL" report.status_extended = f"Step Functions state machine {state_machine.name} does not have logging enabled." findings.append(report) diff --git a/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled_test.py b/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled_test.py index 212267fdf3..801c045f5b 100644 --- a/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled_test.py +++ b/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_logging_enabled/stepfunctions_statemachine_logging_enabled_test.py @@ -74,6 +74,15 @@ def create_state_machine(name, logging_configuration): }, 1, ), # Logging enabled + ( + { + STATE_MACHINE_ARN: create_state_machine( + "TestStateMachine", + None, + ) + }, + 1, + ), # Logging configuration is None ], ) @mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) @@ -104,10 +113,9 @@ def test_stepfunctions_statemachine_logging(state_machines, expected_status): # Additional assertions for specific scenarios if expected_status == 1: - if ( - state_machines[STATE_MACHINE_ARN].logging_configuration.level - == LoggingLevel.OFF - ): + logging_conf = state_machines[STATE_MACHINE_ARN].logging_configuration + + if logging_conf is None or logging_conf.level == LoggingLevel.OFF: assert result[0].status == "FAIL" assert ( result[0].status_extended @@ -123,3 +131,4 @@ def test_stepfunctions_statemachine_logging(state_machines, expected_status): assert result[0].resource_id == STATE_MACHINE_ID assert result[0].resource_arn == STATE_MACHINE_ARN assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource == state_machines[STATE_MACHINE_ARN] From b3014f03b1feb85e7db8c72612a4fcb3daf48378 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 09:13:50 +0100 Subject: [PATCH 078/359] chore(deps): bump actions/setup-python from 5.4.0 to 5.5.0 (#7390) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-build-lint-push-containers.yml | 2 +- .github/workflows/sdk-pull-request.yml | 2 +- .github/workflows/sdk-pypi-release.yml | 2 +- .github/workflows/sdk-refresh-aws-services-regions.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 9c0fd9f667..5904d87673 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -94,7 +94,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml index e3629f2d46..67343650d9 100644 --- a/.github/workflows/sdk-build-lint-push-containers.yml +++ b/.github/workflows/sdk-build-lint-push-containers.yml @@ -62,7 +62,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ env.PYTHON_VERSION }} diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index b637c32f0b..f0adcdbd70 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -50,7 +50,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml index 553d50a4fa..986cee2ada 100644 --- a/.github/workflows/sdk-pypi-release.yml +++ b/.github/workflows/sdk-pypi-release.yml @@ -71,7 +71,7 @@ jobs: pipx install poetry==2.1.1 - name: Setup Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ env.PYTHON_VERSION }} cache: ${{ env.CACHE }} diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index c4b6b9a1bf..9a9d01ea0a 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -28,7 +28,7 @@ jobs: ref: ${{ env.GITHUB_BRANCH }} - name: setup python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: 3.9 #install the python needed From 87c038f0c2b963120ce237807666795316511ac5 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:09:33 +0100 Subject: [PATCH 079/359] fix(rds): hundle Certificate `rds-ca-2019` not found (#7383) --- .../providers/aws/services/rds/rds_service.py | 44 ++++++++----- .../aws/services/rds/rds_service_test.py | 66 +++++++++++++++++++ 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/prowler/providers/aws/services/rds/rds_service.py b/prowler/providers/aws/services/rds/rds_service.py index 320b997bba..9e2a921bdd 100644 --- a/prowler/providers/aws/services/rds/rds_service.py +++ b/prowler/providers/aws/services/rds/rds_service.py @@ -149,24 +149,34 @@ class RDS(AWSService): "describe_certificates" ) if instance.ca_cert: - for page in describe_db_certificates_paginator.paginate( - CertificateIdentifier=instance.ca_cert - ): - for certificate in page["Certificates"]: - instance.cert.append( - Certificate( - id=certificate["CertificateIdentifier"], - arn=certificate["CertificateArn"], - type=certificate["CertificateType"], - valid_from=certificate["ValidFrom"], - valid_till=certificate["ValidTill"], - customer_override=certificate[ - "CustomerOverride" - ], - customer_override_valid_till=certificate.get( - "CustomerOverrideValidTill" - ), + try: + for page in describe_db_certificates_paginator.paginate( + CertificateIdentifier=instance.ca_cert + ): + for certificate in page["Certificates"]: + instance.cert.append( + Certificate( + id=certificate["CertificateIdentifier"], + arn=certificate["CertificateArn"], + type=certificate["CertificateType"], + valid_from=certificate["ValidFrom"], + valid_till=certificate["ValidTill"], + customer_override=certificate[ + "CustomerOverride" + ], + customer_override_valid_till=certificate.get( + "CustomerOverrideValidTill" + ), + ) ) + except ClientError as error: + if error.response["Error"]["Code"] == "CertificateNotFound": + logger.warning( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + else: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) except Exception as error: diff --git a/tests/providers/aws/services/rds/rds_service_test.py b/tests/providers/aws/services/rds/rds_service_test.py index 111a3d1da1..bce34ac9f4 100644 --- a/tests/providers/aws/services/rds/rds_service_test.py +++ b/tests/providers/aws/services/rds/rds_service_test.py @@ -4,6 +4,7 @@ from unittest.mock import patch import botocore from boto3 import client +from botocore.exceptions import ClientError from moto import mock_aws from prowler.providers.aws.services.rds.rds_service import RDS, Certificate, DBInstance @@ -31,6 +32,20 @@ def mock_make_api_call(self, operation_name, kwarg): return make_api_call(self, operation_name, kwarg) +def mock_make_api_call_excepcion_deprecated_cert(self, operation_name, kwarg): + if operation_name == "DescribeCertificates": + raise ClientError( + error_response={ + "Error": { + "Code": "CertificateNotFound", + "Message": "Certificate rds-ca-2019 not found", + } + }, + operation_name=operation_name, + ) + return make_api_call(self, operation_name, kwarg) + + @patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) class Test_RDS_Service: # Test RDS Service @@ -226,6 +241,57 @@ class Test_RDS_Service: assert not cert.customer_override assert cert.customer_override_valid_till == datetime(2025, 1, 1) + @mock_aws + def test_describe_db_certificate_with_deprecated_cert_not_found(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_excepcion_deprecated_cert, + ): + rds_client = mock.MagicMock + rds_client.db_instances = { + "arn:aws:rds:us-east-1:123456789012:db:db-master-1": DBInstance( + id="db-master-1", + region=AWS_REGION_US_EAST_1, + endpoint={ + "Address": "db-master-1.aaaaaaaaaa.us-east-1.rds.amazonaws.com", + "Port": 5432, + }, + status="available", + public=True, + encrypted=True, + backup_retention_period=10, + cloudwatch_logs=["audit", "error"], + deletion_protection=True, + auto_minor_version_upgrade=True, + multi_az=True, + cluster_id="cluster-postgres", + tags=[{"Key": "test", "Value": "test"}], + parameter_groups=["test"], + copy_tags_to_snapshot=True, + ca_cert="rds-cert-2019", + arn="arn:aws:rds:us-east-1:123456789012:db:db-master-1", + engine="postgres", + engine_version="9.6.9", + username="test", + iam_auth=False, + cert=[], + ) + } + + with mock.patch( + "prowler.providers.aws.services.rds.rds_service.RDS", + new=rds_client, + ): + from prowler.providers.aws.services.rds.rds_service import RDS + + rds = RDS(rds_client) + assert len(rds.db_instances) == 1 + db_instance_arn, db_instance = next(iter(rds.db_instances.items())) + assert db_instance.id == "db-master-1" + assert db_instance.region == AWS_REGION_US_EAST_1 + # No certificate should be found due to the exception + assert len(db_instance.cert) == 0 + # Test RDS Describe DB Snapshots @mock_aws def test_describe_db_snapshots(self): From 34f03ca110566663baf7048fd7a2183c8fc4f74c Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Thu, 27 Mar 2025 11:10:07 +0100 Subject: [PATCH 080/359] chore(regions_update): Changes in regions for AWS services (#7391) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 25609b133b..8e866526bc 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -7478,6 +7478,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -7491,6 +7492,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -8253,6 +8255,7 @@ "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ap-southeast-5", "ca-central-1", "eu-central-1", "eu-north-1", @@ -8377,6 +8380,7 @@ "qbusiness": { "regions": { "aws": [ + "ap-southeast-2", "eu-west-1", "us-east-1", "us-west-2" From 9d65fb0bf29b409b30eeeafa73c2fd13615d7082 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:12:55 +0200 Subject: [PATCH 081/359] chore(deps): bump trufflesecurity/trufflehog from 3.88.18 to 3.88.20 (#7394) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/find-secrets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml index 0544906f16..59e929394f 100644 --- a/.github/workflows/find-secrets.yml +++ b/.github/workflows/find-secrets.yml @@ -11,7 +11,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@ded5f45b92c00939718787ce586b520bbe795f3b # v3.88.18 + uses: trufflesecurity/trufflehog@793c09da0f612a946a511869d1013f2db37824de # v3.88.20 with: path: ./ base: ${{ github.event.repository.default_branch }} From bbed445efae8b900062510d2dca4ad33d07bda91 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:13:19 +0200 Subject: [PATCH 082/359] chore(sentry): ignore exception when aws service not available in a region (#7352) --- api/src/backend/config/settings/sentry.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py index bb76173b6c..f6ac512cf2 100644 --- a/api/src/backend/config/settings/sentry.py +++ b/api/src/backend/config/settings/sentry.py @@ -54,6 +54,8 @@ IGNORED_EXCEPTIONS = [ "AzureClientIdAndClientSecretNotBelongingToTenantIdError", "AzureHTTPResponseError", "Error with credentials provided", + # AWS Service is not available in a region + "EndpointConnectionError", ] From 6a3db10fdadd5a2347adc9505faee87f29ea14bc Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 31 Mar 2025 10:18:53 +0200 Subject: [PATCH 083/359] chore(regions_update): Changes in regions for AWS services (#7395) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 8e866526bc..d5adfbc258 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -9467,6 +9467,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -9480,6 +9481,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From e06a33de84ce3800a6b9dc9618a4ab34e99a6665 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:24:47 +0200 Subject: [PATCH 084/359] feat(entra): add new check `entra_managed_device_required_for_mfa_registration` (#7203) Co-authored-by: MrCloudSec --- ...aged_device_required_for_authentication.py | 2 +- .../__init__.py | 0 ...equired_for_mfa_registration.metadata.json | 30 ++ ...ed_device_required_for_mfa_registration.py | 72 +++++ .../services/entra/entra_service.py | 63 ++-- ...a_enabled_for_administrative_roles_test.py | 23 +- ..._admin_portals_role_limited_access_test.py | 6 +- ...in_users_sign_in_frequency_enabled_test.py | 24 +- ...ty_protection_sign_in_risk_enabled_test.py | 7 +- ...ntity_protection_user_risk_enabled_test.py | 7 +- ...device_required_for_authentication_test.py | 6 +- ...vice_required_for_mfa_registration_test.py | 293 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 23 +- 13 files changed, 504 insertions(+), 52 deletions(-) create mode 100644 prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py create mode 100644 tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py index 08ba22de9a..6825725a52 100644 --- a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py +++ b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py @@ -8,7 +8,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( class entra_managed_device_required_for_authentication(Check): - """Check if Conditional Access policies deny access to the Microsoft 365 + """Check if Conditional Access policies enforce managed device requirement for authentication. This check ensures that Conditional Access policies are in place to enforce managed device requirement for authentication. """ diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json new file mode 100644 index 0000000000..871d9f318e --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_managed_device_required_for_mfa_registration", + "CheckTitle": "Ensure that only managed devices are required for MFA registration", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Conditional Access Policy", + "Description": "Ensure that only managed devices are required for MFA registration. This ensures that users enroll MFA using secure, organization-controlled devices.", + "Risk": "If users are allowed to register MFA on unmanaged or potentially compromised devices, attackers with stolen credentials may register their own MFA methods, effectively locking out legitimate users and taking over accounts. This increases the risk of unauthorized access, data breaches, and privilege escalation.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/overview", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com. 2. Click expand Protection > Conditional Access select Policies. 3. Create a new policy by selecting New policy. Under Users include All users. Under Target resources select User actions and check Register security information. Under Grant select Grant access. Check Require multifactor authentication and Require Microsoft Entra hybrid joined device. Choose Require one of the selected controls and click Select at the bottom. 4. Under Enable policy set it to Report Only until the organization is ready to enable it. 5. Click Create.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enforce MFA registration only from managed devices by requiring compliance through Intune or Entra hybrid join. This ensures that users enroll MFA using secure, organization-controlled devices.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-all-users-device-registration" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py new file mode 100644 index 0000000000..7fc446c956 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py @@ -0,0 +1,72 @@ +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, + GrantControlOperator, + UserAction, +) + + +class entra_managed_device_required_for_mfa_registration(Check): + """Check if Conditional Access policies enforce MFA registration on a managed device. + + This check ensures that Conditional Access policies are in place to enforce MFA registration on a managed device. + """ + + def execute(self) -> list[CheckReportMicrosoft365]: + """Execute the check to ensure that Conditional Access policies enforce MFA registration on a managed device. + + Returns: + list[CheckReportMicrosoft365]: A list containing the results of the check. + """ + findings = [] + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource={}, + resource_name="Conditional Access Policies", + resource_id="conditionalAccessPolicies", + ) + report.status = "FAIL" + report.status_extended = "No Conditional Access Policy requires a managed device for MFA registration." + + for policy in entra_client.conditional_access_policies.values(): + if policy.state == ConditionalAccessPolicyState.DISABLED: + continue + + if "All" not in policy.conditions.user_conditions.included_users: + continue + + if ( + UserAction.REGISTER_SECURITY_INFO + not in policy.conditions.application_conditions.included_user_actions + ): + continue + + if ( + ConditionalAccessGrantControl.DOMAIN_JOINED_DEVICE + not in policy.grant_controls.built_in_controls + or ConditionalAccessGrantControl.MFA + not in policy.grant_controls.built_in_controls + ): + continue + + if policy.grant_controls.operator == GrantControlOperator.OR: + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.display_name, + resource_id=policy.id, + ) + if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING: + report.status = "FAIL" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports the requirement of a managed device for MFA registration but does not enforce it." + else: + report.status = "PASS" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' does require a managed device for MFA registration." + break + + findings.append(report) + + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 9b83f98fc4..7dc91746ee 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -119,6 +119,14 @@ class Entra(Microsoft365Service): [], ) ], + included_user_actions=[ + UserAction(user_action) + for user_action in getattr( + policy.conditions.applications, + "include_user_actions", + [], + ) + ], ), user_conditions=UsersConditions( included_groups=[ @@ -261,31 +269,6 @@ class Entra(Microsoft365Service): ) return conditional_access_policies - async def _get_organization(self): - logger.info("Entra - Getting organizations...") - organizations = [] - try: - org_data = await self.client.organization.get() - for org in org_data.value: - sync_enabled = ( - org.on_premises_sync_enabled - if org.on_premises_sync_enabled is not None - else False - ) - - organization = Organization( - id=org.id, - name=org.display_name, - on_premises_sync_enabled=sync_enabled, - ) - organizations.append(organization) - except Exception as error: - logger.error( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) - - return organizations - async def _get_admin_consent_policy(self): logger.info("Entra - Getting group settings...") admin_consent_policy = None @@ -323,6 +306,31 @@ class Entra(Microsoft365Service): ) return groups + async def _get_organization(self): + logger.info("Entra - Getting organizations...") + organizations = [] + try: + org_data = await self.client.organization.get() + for org in org_data.value: + sync_enabled = ( + org.on_premises_sync_enabled + if org.on_premises_sync_enabled is not None + else False + ) + + organization = Organization( + id=org.id, + name=org.display_name, + on_premises_sync_enabled=sync_enabled, + ) + organizations.append(organization) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + return organizations + class ConditionalAccessPolicyState(Enum): ENABLED = "enabled" @@ -330,9 +338,14 @@ class ConditionalAccessPolicyState(Enum): ENABLED_FOR_REPORTING = "enabledForReportingButNotEnforced" +class UserAction(Enum): + REGISTER_SECURITY_INFO = "urn:user:registersecurityinfo" + + class ApplicationsConditions(BaseModel): included_applications: List[str] excluded_applications: List[str] + included_user_actions: List[UserAction] class UsersConditions(BaseModel): diff --git a/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py b/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py index ed30be2c7a..4492ac809c 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py +++ b/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py @@ -7,8 +7,8 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( ConditionalAccessPolicy, ConditionalAccessPolicyState, Conditions, - GrantControls, GrantControlOperator, + GrantControls, PersistentBrowser, SessionControls, SignInFrequency, @@ -84,7 +84,9 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: display_name="Disabled Policy", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -158,7 +160,9 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: display_name="No Admin Roles Policy", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -234,6 +238,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: application_conditions=ApplicationsConditions( included_applications=["MicrosoftAdminPortals"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -312,7 +317,9 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -389,7 +396,9 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -482,7 +491,9 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py b/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py index 506d4908ae..71eaaa4dd4 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py +++ b/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py @@ -83,7 +83,9 @@ class Test_entra_admin_portals_role_limited_access: display_name="Test", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=[], excluded_applications=[] + included_applications=[], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -157,6 +159,7 @@ class Test_entra_admin_portals_role_limited_access: application_conditions=ApplicationsConditions( included_applications=["MicrosoftAdminPortals"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -234,6 +237,7 @@ class Test_entra_admin_portals_role_limited_access: application_conditions=ApplicationsConditions( included_applications=["MicrosoftAdminPortals"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py b/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py index b3458c217d..9c2cfa7aa1 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py +++ b/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py @@ -85,7 +85,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name="Test", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=[], excluded_applications=[] + included_applications=[], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -159,7 +161,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -255,7 +259,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -348,7 +354,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -441,7 +449,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -537,7 +547,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled: display_name=display_name, conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=["All"], excluded_applications=[] + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py b/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py index fd6ff82a91..a1c6c48f78 100644 --- a/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py +++ b/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py @@ -84,7 +84,9 @@ class Test_entra_identity_protection_sign_in_risk_enabled: display_name="Test", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=[], excluded_applications=[] + included_applications=[], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -160,6 +162,7 @@ class Test_entra_identity_protection_sign_in_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -242,6 +245,7 @@ class Test_entra_identity_protection_sign_in_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -324,6 +328,7 @@ class Test_entra_identity_protection_sign_in_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py b/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py index e1f7626701..ead5b42d61 100644 --- a/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py +++ b/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py @@ -84,7 +84,9 @@ class Test_entra_identity_protection_user_risk_enabled: display_name="Test", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=[], excluded_applications=[] + included_applications=[], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -159,6 +161,7 @@ class Test_entra_identity_protection_user_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -240,6 +243,7 @@ class Test_entra_identity_protection_user_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -321,6 +325,7 @@ class Test_entra_identity_protection_user_risk_enabled: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py b/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py index 18fa79199b..d40986b56c 100644 --- a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py +++ b/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py @@ -83,7 +83,9 @@ class Test_entra_managed_device_required_for_authentication: display_name="Test", conditions=Conditions( application_conditions=ApplicationsConditions( - included_applications=[], excluded_applications=[] + included_applications=[], + excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -157,6 +159,7 @@ class Test_entra_managed_device_required_for_authentication: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], @@ -238,6 +241,7 @@ class Test_entra_managed_device_required_for_authentication: application_conditions=ApplicationsConditions( included_applications=["All"], excluded_applications=[], + included_user_actions=[], ), user_conditions=UsersConditions( included_groups=[], diff --git a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py b/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py new file mode 100644 index 0000000000..11899eb574 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py @@ -0,0 +1,293 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.microsoft365.services.entra.entra_service import ( + ApplicationsConditions, + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, + Conditions, + GrantControlOperator, + GrantControls, + PersistentBrowser, + SessionControls, + SignInFrequency, + SignInFrequencyInterval, + UserAction, + UsersConditions, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + DOMAIN, + set_mocked_microsoft365_provider, +) + + +class Test_entra_managed_device_required_for_mfa_registration: + def test_entra_no_conditional_access_policies(self): + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + entra_managed_device_required_for_mfa_registration, + ) + + entra_client.conditional_access_policies = {} + + check = entra_managed_device_required_for_mfa_registration() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy requires a managed device for MFA registration." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_managed_device_disabled(self): + id = str(uuid4()) + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + entra_managed_device_required_for_mfa_registration, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name="Test", + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=[], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=[], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[], operator=GrantControlOperator.OR + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.TIME_BASED, + ), + ), + state=ConditionalAccessPolicyState.DISABLED, + ) + } + + check = entra_managed_device_required_for_mfa_registration() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy requires a managed device for MFA registration." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_managed_device_enabled_for_reporting(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + entra_managed_device_required_for_mfa_registration, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[UserAction.REGISTER_SECURITY_INFO], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ + ConditionalAccessGrantControl.MFA, + ConditionalAccessGrantControl.DOMAIN_JOINED_DEVICE, + ], + operator=GrantControlOperator.OR, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.TIME_BASED, + ), + ), + state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING, + ) + } + + check = entra_managed_device_required_for_mfa_registration() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' reports the requirement of a managed device for MFA registration but does not enforce it." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" + + def test_entra_managed_device_enabled(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + entra_managed_device_required_for_mfa_registration, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[UserAction.REGISTER_SECURITY_INFO], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ + ConditionalAccessGrantControl.MFA, + ConditionalAccessGrantControl.DOMAIN_JOINED_DEVICE, + ], + operator=GrantControlOperator.OR, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.TIME_BASED, + ), + ), + state=ConditionalAccessPolicyState.ENABLED, + ) + } + + check = entra_managed_device_required_for_mfa_registration() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' does require a managed device for MFA registration." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py index 5816d78305..e9fb9fb2eb 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py @@ -19,6 +19,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequency, SignInFrequencyInterval, SignInFrequencyType, + UserAction, UsersConditions, ) from tests.providers.microsoft365.microsoft365_fixtures import ( @@ -42,16 +43,6 @@ async def mock_entra_get_authorization_policy(_): ) -async def mock_entra_get_organization(_): - return [ - Organization( - id="org1", - name="Organization 1", - on_premises_sync_enabled=True, - ) - ] - - async def mock_entra_get_conditional_access_policies(_): return { "id-1": ConditionalAccessPolicy( @@ -61,6 +52,7 @@ async def mock_entra_get_conditional_access_policies(_): application_conditions=ApplicationsConditions( included_applications=["app-1", "app-2"], excluded_applications=["app-3", "app-4"], + included_user_actions=[UserAction.REGISTER_SECURITY_INFO], ), user_conditions=UsersConditions( included_groups=["group-1", "group-2"], @@ -117,6 +109,16 @@ async def mock_entra_get_admin_consent_policy(_): ) +async def mock_entra_get_organization(_): + return [ + Organization( + id="org1", + name="Organization 1", + on_premises_sync_enabled=True, + ) + ] + + class Test_Entra_Service: def test_get_client(self): admincenter_client = Entra( @@ -160,6 +162,7 @@ class Test_Entra_Service: application_conditions=ApplicationsConditions( included_applications=["app-1", "app-2"], excluded_applications=["app-3", "app-4"], + included_user_actions=[UserAction.REGISTER_SECURITY_INFO], ), user_conditions=UsersConditions( included_groups=["group-1", "group-2"], From 08690068fc87cf8be26c9efd70624e4675d76083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Mon, 31 Mar 2025 12:25:58 +0200 Subject: [PATCH 085/359] feat(findings): Handle muted findings in API and UI (#7378) Co-authored-by: Pablo Lara --- api/CHANGELOG.md | 1 + api/src/backend/api/filters.py | 11 ++---- .../api/migrations/0015_finding_muted.py | 26 +++++++++++++ api/src/backend/api/models.py | 2 +- api/src/backend/api/specs/v1.yaml | 38 +++++++++++-------- api/src/backend/api/tests/test_views.py | 2 + api/src/backend/api/v1/serializers.py | 1 + api/src/backend/conftest.py | 1 + api/src/backend/tasks/jobs/scan.py | 29 +++++++------- api/src/backend/tasks/tests/test_scan.py | 1 + ui/CHANGELOG.md | 1 + ui/components/filters/data-filters.ts | 2 +- ui/components/findings/index.ts | 1 + ui/components/findings/muted.tsx | 19 ++++++++++ .../findings/table/column-findings.tsx | 22 ++++++++--- .../findings/table/finding-detail.tsx | 25 +++++++----- ui/components/icons/Icons.tsx | 28 ++++++++++++++ .../table/column-new-findings-to-date.tsx | 16 ++++++-- ui/components/ui/table/severity-badge.tsx | 2 +- .../ui/table/status-finding-badge.tsx | 6 ++- ui/types/components.ts | 3 +- 21 files changed, 174 insertions(+), 63 deletions(-) create mode 100644 api/src/backend/api/migrations/0015_finding_muted.py create mode 100644 ui/components/findings/index.ts create mode 100644 ui/components/findings/muted.tsx diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 4fe334b562..09cc4369ae 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. - Support for developing new integrations [(#7167)](https://github.com/prowler-cloud/prowler/pull/7167). - HTTP Security Headers [(#7289)](https://github.com/prowler-cloud/prowler/pull/7289). - New endpoint to get the compliance overviews metadata [(#7333)](https://github.com/prowler-cloud/prowler/pull/7333). +- Support for muted findings [(#7378)](https://github.com/prowler-cloud/prowler/pull/7378). --- diff --git a/api/src/backend/api/filters.py b/api/src/backend/api/filters.py index dbd73b41db..fc16cf394b 100644 --- a/api/src/backend/api/filters.py +++ b/api/src/backend/api/filters.py @@ -287,6 +287,9 @@ class FindingFilter(FilterSet): status = ChoiceFilter(choices=StatusChoices.choices) severity = ChoiceFilter(choices=SeverityChoices) impact = ChoiceFilter(choices=SeverityChoices) + muted = BooleanFilter( + help_text="If this filter is not provided, muted and non-muted findings will be returned." + ) resources = UUIDInFilter(field_name="resource__id", lookup_expr="in") @@ -614,12 +617,6 @@ class ScanSummaryFilter(FilterSet): field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices ) region = CharFilter(field_name="region") - muted_findings = BooleanFilter(method="filter_muted_findings") - - def filter_muted_findings(self, queryset, name, value): - if not value: - return queryset.exclude(muted__gt=0) - return queryset class Meta: model = ScanSummary @@ -630,8 +627,6 @@ class ScanSummaryFilter(FilterSet): class ServiceOverviewFilter(ScanSummaryFilter): - muted_findings = None - def is_valid(self): # Check if at least one of the inserted_at filters is present inserted_at_filters = [ diff --git a/api/src/backend/api/migrations/0015_finding_muted.py b/api/src/backend/api/migrations/0015_finding_muted.py new file mode 100644 index 0000000000..3cb20f871b --- /dev/null +++ b/api/src/backend/api/migrations/0015_finding_muted.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.5 on 2025-03-25 11:29 + +from django.db import migrations, models + +import api.db_utils + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0014_integrations"), + ] + + operations = [ + migrations.AddField( + model_name="finding", + name="muted", + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name="finding", + name="status", + field=api.db_utils.StatusEnumField( + choices=[("FAIL", "Fail"), ("PASS", "Pass"), ("MANUAL", "Manual")] + ), + ), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 0ac9f912a0..e22f37a07d 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -59,7 +59,6 @@ class StatusChoices(models.TextChoices): FAIL = "FAIL", _("Fail") PASS = "PASS", _("Pass") MANUAL = "MANUAL", _("Manual") - MUTED = "MUTED", _("Muted") class StateChoices(models.TextChoices): @@ -656,6 +655,7 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel): tags = models.JSONField(default=dict, null=True, blank=True) check_id = models.CharField(max_length=100, blank=False, null=False) check_metadata = models.JSONField(default=dict, null=False) + muted = models.BooleanField(default=False, null=False) # Relationships scan = models.ForeignKey(to=Scan, related_name="findings", on_delete=models.CASCADE) diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 36f67c0e75..30c9dbb675 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -294,6 +294,7 @@ paths: - inserted_at - updated_at - first_seen_at + - muted - url - scan - resources @@ -402,6 +403,12 @@ paths: type: string format: date description: Maximum date range is 7 days. + - in: query + name: filter[muted] + schema: + type: boolean + description: If this filter is not provided, muted and non-muted findings + will be returned. - in: query name: filter[provider] schema: @@ -633,13 +640,11 @@ paths: enum: - FAIL - MANUAL - - MUTED - PASS description: |- * `FAIL` - Fail * `PASS` - Pass * `MANUAL` - Manual - * `MUTED` - Muted - in: query name: filter[status__in] schema: @@ -756,6 +761,7 @@ paths: - inserted_at - updated_at - first_seen_at + - muted - url - scan - resources @@ -909,6 +915,12 @@ paths: type: string format: date description: Maximum date range is 7 days. + - in: query + name: filter[muted] + schema: + type: boolean + description: If this filter is not provided, muted and non-muted findings + will be returned. - in: query name: filter[provider] schema: @@ -1140,13 +1152,11 @@ paths: enum: - FAIL - MANUAL - - MUTED - PASS description: |- * `FAIL` - Fail * `PASS` - Pass * `MANUAL` - Manual - * `MUTED` - Muted - in: query name: filter[status__in] schema: @@ -1338,6 +1348,12 @@ paths: type: string format: date description: Maximum date range is 7 days. + - in: query + name: filter[muted] + schema: + type: boolean + description: If this filter is not provided, muted and non-muted findings + will be returned. - in: query name: filter[provider] schema: @@ -1569,13 +1585,11 @@ paths: enum: - FAIL - MANUAL - - MUTED - PASS description: |- * `FAIL` - Fail * `PASS` - Pass * `MANUAL` - Manual - * `MUTED` - Muted - in: query name: filter[status__in] schema: @@ -2019,10 +2033,6 @@ paths: schema: type: string format: date-time - - in: query - name: filter[muted_findings] - schema: - type: boolean - in: query name: filter[provider_id] schema: @@ -2180,10 +2190,6 @@ paths: schema: type: string format: date-time - - in: query - name: filter[muted_findings] - schema: - type: boolean - in: query name: filter[provider_id] schema: @@ -6238,13 +6244,11 @@ components: - FAIL - PASS - MANUAL - - MUTED type: string description: |- * `FAIL` - Fail * `PASS` - Pass * `MANUAL` - Manual - * `MUTED` - Muted status_extended: type: string nullable: true @@ -6280,6 +6284,8 @@ components: format: date-time readOnly: true nullable: true + muted: + type: boolean required: - uid - status diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index c11c0dec24..002af353da 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -2693,6 +2693,8 @@ class TestFindingViewSet: # ("resource_tags", "key:value", 2), # ("resource_tags", "not:exists", 0), # ("resource_tags", "not:exists,key:value", 2), + ("muted", True, 1), + ("muted", False, 1), ] ), ) diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 8d45e495ea..96fe46eb85 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -1091,6 +1091,7 @@ class FindingSerializer(RLSSerializer): "inserted_at", "updated_at", "first_seen_at", + "muted", "url", # Relationships "scan", diff --git a/api/src/backend/conftest.py b/api/src/backend/conftest.py index 097998a976..acd33ea4d1 100644 --- a/api/src/backend/conftest.py +++ b/api/src/backend/conftest.py @@ -655,6 +655,7 @@ def findings_fixture(scans_fixture, resources_fixture): "Description": "test description orange juice", }, first_seen_at="2024-01-02T00:00:00Z", + muted=True, ) finding2.add_resources([resource2]) diff --git a/api/src/backend/tasks/jobs/scan.py b/api/src/backend/tasks/jobs/scan.py index 5c165b4cb4..998995731e 100644 --- a/api/src/backend/tasks/jobs/scan.py +++ b/api/src/backend/tasks/jobs/scan.py @@ -267,6 +267,7 @@ def perform_prowler_scan( check_id=finding.check_id, scan=scan_instance, first_seen_at=last_first_seen_at, + muted=finding.muted, ) finding_instance.add_resources([resource_instance]) @@ -402,21 +403,21 @@ def aggregate_findings(tenant_id: str, scan_id: str): ).annotate( fail=Sum( Case( - When(status="FAIL", then=1), + When(status="FAIL", muted=False, then=1), default=0, output_field=IntegerField(), ) ), _pass=Sum( Case( - When(status="PASS", then=1), + When(status="PASS", muted=False, then=1), default=0, output_field=IntegerField(), ) ), - muted=Sum( + muted_count=Sum( Case( - When(status="MUTED", then=1), + When(muted=True, then=1), default=0, output_field=IntegerField(), ) @@ -424,63 +425,63 @@ def aggregate_findings(tenant_id: str, scan_id: str): total=Count("id"), new=Sum( Case( - When(delta="new", then=1), + When(delta="new", muted=False, then=1), default=0, output_field=IntegerField(), ) ), changed=Sum( Case( - When(delta="changed", then=1), + When(delta="changed", muted=False, then=1), default=0, output_field=IntegerField(), ) ), unchanged=Sum( Case( - When(delta__isnull=True, then=1), + When(delta__isnull=True, muted=False, then=1), default=0, output_field=IntegerField(), ) ), fail_new=Sum( Case( - When(delta="new", status="FAIL", then=1), + When(delta="new", status="FAIL", muted=False, then=1), default=0, output_field=IntegerField(), ) ), fail_changed=Sum( Case( - When(delta="changed", status="FAIL", then=1), + When(delta="changed", status="FAIL", muted=False, then=1), default=0, output_field=IntegerField(), ) ), pass_new=Sum( Case( - When(delta="new", status="PASS", then=1), + When(delta="new", status="PASS", muted=False, then=1), default=0, output_field=IntegerField(), ) ), pass_changed=Sum( Case( - When(delta="changed", status="PASS", then=1), + When(delta="changed", status="PASS", muted=False, then=1), default=0, output_field=IntegerField(), ) ), muted_new=Sum( Case( - When(delta="new", status="MUTED", then=1), + When(delta="new", muted=True, then=1), default=0, output_field=IntegerField(), ) ), muted_changed=Sum( Case( - When(delta="changed", status="MUTED", then=1), + When(delta="changed", muted=True, then=1), default=0, output_field=IntegerField(), ) @@ -498,7 +499,7 @@ def aggregate_findings(tenant_id: str, scan_id: str): region=agg["resources__region"], fail=agg["fail"], _pass=agg["_pass"], - muted=agg["muted"], + muted=agg["muted_count"], total=agg["total"], new=agg["new"], changed=agg["changed"], diff --git a/api/src/backend/tasks/tests/test_scan.py b/api/src/backend/tasks/tests/test_scan.py index 78ba36fde8..66d1472c7b 100644 --- a/api/src/backend/tasks/tests/test_scan.py +++ b/api/src/backend/tasks/tests/test_scan.py @@ -107,6 +107,7 @@ class TestPerformScan: finding.service_name = "service_name" finding.resource_type = "resource_type" finding.resource_tags = {"tag1": "value1", "tag2": "value2"} + finding.muted = False finding.raw = {} # Mock the ProwlerScan instance diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 4500c57bd4..ea7a7565aa 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Added `one-time scan` feature: Adds support for single scan execution. [(#7188)](https://github.com/prowler-cloud/prowler/pull/7188) - Accepted invitations can no longer be edited. [(#7198)](https://github.com/prowler-cloud/prowler/pull/7198) - Added download column in scans table to download reports for completed scans. [(#7353)](https://github.com/prowler-cloud/prowler/pull/7353) +- Show muted icon when a finding is muted. [(#7378)](https://github.com/prowler-cloud/prowler/pull/7378) #### 🔄 Changed diff --git a/ui/components/filters/data-filters.ts b/ui/components/filters/data-filters.ts index 36594ec50b..58709ec167 100644 --- a/ui/components/filters/data-filters.ts +++ b/ui/components/filters/data-filters.ts @@ -42,7 +42,7 @@ export const filterFindings = [ { key: "status__in", labelCheckboxGroup: "Status", - values: ["PASS", "FAIL", "MANUAL", "MUTED"], + values: ["PASS", "FAIL", "MANUAL"], }, { key: "delta__in", diff --git a/ui/components/findings/index.ts b/ui/components/findings/index.ts new file mode 100644 index 0000000000..2e2bece9f7 --- /dev/null +++ b/ui/components/findings/index.ts @@ -0,0 +1 @@ +export * from "./muted"; diff --git a/ui/components/findings/muted.tsx b/ui/components/findings/muted.tsx new file mode 100644 index 0000000000..23c1422cf6 --- /dev/null +++ b/ui/components/findings/muted.tsx @@ -0,0 +1,19 @@ +import { Tooltip } from "@nextui-org/react"; + +import { MutedIcon } from "../icons"; + +interface MutedProps { + isMuted: boolean; +} + +export const Muted = ({ isMuted }: MutedProps) => { + if (isMuted === false) return null; + + return ( + +
+ +
+
+ ); +}; diff --git a/ui/components/findings/table/column-findings.tsx b/ui/components/findings/table/column-findings.tsx index f4560f3396..f341ad26ea 100644 --- a/ui/components/findings/table/column-findings.tsx +++ b/ui/components/findings/table/column-findings.tsx @@ -14,6 +14,8 @@ import { } from "@/components/ui/table"; import { FindingProps } from "@/types"; +import { Muted } from "../muted"; + const getFindingsData = (row: { original: FindingProps }) => { return row.original; }; @@ -91,10 +93,18 @@ export const ColumnFindings: ColumnDef[] = [ ), cell: ({ row }) => { const { checktitle } = getFindingsMetadata(row); + const { + attributes: { muted }, + } = getFindingsData(row); return ( -

- {checktitle} -

+
+

+ {checktitle} +

+ + + +
); }, }, @@ -124,7 +134,7 @@ export const ColumnFindings: ColumnDef[] = [ attributes: { status }, } = getFindingsData(row); - return ; + return ; }, }, { @@ -169,7 +179,7 @@ export const ColumnFindings: ColumnDef[] = [ const region = getResourceData(row, "region"); return ( -
+
{typeof region === "string" ? region : "Invalid region"}
); @@ -180,7 +190,7 @@ export const ColumnFindings: ColumnDef[] = [ header: "Service", cell: ({ row }) => { const { servicename } = getFindingsMetadata(row); - return

{servicename}

; + return

{servicename}

; }, }, { diff --git a/ui/components/findings/table/finding-detail.tsx b/ui/components/findings/table/finding-detail.tsx index 82706b2afd..1c4044fd52 100644 --- a/ui/components/findings/table/finding-detail.tsx +++ b/ui/components/findings/table/finding-detail.tsx @@ -12,6 +12,8 @@ import { import { SeverityBadge } from "@/components/ui/table/severity-badge"; import { FindingProps } from "@/types"; +import { Muted } from "../muted"; + const renderValue = (value: string | null | undefined) => { return value && value.trim() !== "" ? value : "-"; }; @@ -66,17 +68,20 @@ export const FindingDetail = ({ {renderValue(attributes.check_metadata.checktitle)}
+
+ -
- {renderValue(attributes.status)} +
+ {renderValue(attributes.status)} +
diff --git a/ui/components/icons/Icons.tsx b/ui/components/icons/Icons.tsx index 4cf36bc6c7..7d7ba0f1ae 100644 --- a/ui/components/icons/Icons.tsx +++ b/ui/components/icons/Icons.tsx @@ -1025,3 +1025,31 @@ export const GCPIcon: React.FC = ({ ); }; + +export const MutedIcon: React.FC = ({ + size, + height, + width, + ...props +}) => { + return ( + + ); +}; diff --git a/ui/components/overview/new-findings-table/table/column-new-findings-to-date.tsx b/ui/components/overview/new-findings-table/table/column-new-findings-to-date.tsx index 87f2f28784..8bdae43ef9 100644 --- a/ui/components/overview/new-findings-table/table/column-new-findings-to-date.tsx +++ b/ui/components/overview/new-findings-table/table/column-new-findings-to-date.tsx @@ -10,6 +10,8 @@ import { TriggerSheet } from "@/components/ui/sheet"; import { SeverityBadge, StatusFindingBadge } from "@/components/ui/table"; import { FindingProps } from "@/types"; +import { Muted } from "../../../findings/muted"; + const getFindingsData = (row: { original: FindingProps }) => { return row.original; }; @@ -71,10 +73,18 @@ export const ColumnNewFindingsToDate: ColumnDef[] = [ header: "Finding", cell: ({ row }) => { const { checktitle } = getFindingsMetadata(row); + const { + attributes: { muted }, + } = getFindingsData(row); return ( -

- {checktitle} -

+
+

+ {checktitle} +

+ + + +
); }, }, diff --git a/ui/components/ui/table/severity-badge.tsx b/ui/components/ui/table/severity-badge.tsx index d15c8a098a..3c03b8d99b 100644 --- a/ui/components/ui/table/severity-badge.tsx +++ b/ui/components/ui/table/severity-badge.tsx @@ -45,7 +45,7 @@ export const SeverityBadge = ({ severity }: { severity: Severity }) => { color={color} endContent={getSeverityIcon(severity)} > - {severity} + {severity} ); }; diff --git a/ui/components/ui/table/status-finding-badge.tsx b/ui/components/ui/table/status-finding-badge.tsx index 3dfc6e2613..b9532d3b5d 100644 --- a/ui/components/ui/table/status-finding-badge.tsx +++ b/ui/components/ui/table/status-finding-badge.tsx @@ -25,13 +25,15 @@ export const StatusFindingBadge = ({ return ( - {status} + + {status.charAt(0).toUpperCase() + status.slice(1).toLowerCase()} + ); }; diff --git a/ui/types/components.ts b/ui/types/components.ts index 342e4d401f..5b2aa59437 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -597,10 +597,11 @@ export interface FindingProps { attributes: { uid: string; delta: "new" | "changed" | null; - status: "PASS" | "FAIL" | "MANUAL" | "MUTED"; + status: "PASS" | "FAIL" | "MANUAL"; status_extended: string; severity: "informational" | "low" | "medium" | "high" | "critical"; check_id: string; + muted: boolean; check_metadata: { risk: string; notes: string; From 9578281b4f689deffd8cad4c36f5ba63f3c32b29 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:32:51 +0200 Subject: [PATCH 086/359] feat(entra): add new check `entra_policy_restricts_user_consent_for_apps` (#7225) --- ...t_user_cannot_create_tenants.metadata.json | 2 +- .../__init__.py | 0 ...tricts_user_consent_for_apps.metadata.json | 30 ++++ ..._policy_restricts_user_consent_for_apps.py | 47 ++++++ ...cy_restricts_user_consent_for_apps_test.py | 150 ++++++++++++++++++ 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py create mode 100644 tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json b/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json index 12a0da5cf9..df7e7f30db 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json +++ b/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json @@ -7,7 +7,7 @@ "SubServiceName": "", "ResourceIdTemplate": "", "Severity": "high", - "ResourceType": "#microsoft.graph.authorizationPolicy", + "ResourceType": "Authorization Policy", "Description": "Require administrators or appropriately delegated users to create new tenants.", "Risk": "It is recommended to only allow an administrator to create new tenants. This prevent users from creating new Azure AD or Azure AD B2C tenants and ensures that only authorized users are able to do so.", "RelatedUrl": "https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions", diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py b/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json b/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json new file mode 100644 index 0000000000..066cb1fa77 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_policy_restricts_user_consent_for_apps", + "CheckTitle": "Ensure 'User consent for applications' is set to 'Do not allow user consent'", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Authorization Policy", + "Description": "Require administrators to provide consent for applications before use.", + "Risk": "If Microsoft Entra ID is running as an identity provider for third-party applications, permissions and consent should be limited to administrators or pre-approved. Malicious applications may attempt to exfiltrate data or abuse privileged user accounts.", + "RelatedUrl": "https://learn.microsoft.com/en-gb/entra/identity/enterprise-apps/configure-user-consent?pivots=portal", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Entra admin center (https://entra.microsoft.com/); 2. Click to expand Identity > Applications and select Enterprise applications; 3. Under Security select Consent and permissions > User consent settings; 4. Under User consent for applications select Do not allow user consent; 5. Click the Save option at the top of the window.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable user consent for applications in the Microsoft Entra admin center. This ensures that end users and group owners cannot grant consent to applications, requiring administrator approval for all future consent operations, thereby reducing the risk of unauthorized access to company data.", + "Url": "https://learn.microsoft.com/en-gb/entra/identity/enterprise-apps/configure-user-consent?pivots=portal" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Enforcing this setting may create additional requests that administrators need to review." +} diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py b/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py new file mode 100644 index 0000000000..a8ac22f008 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py @@ -0,0 +1,47 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client + + +class entra_policy_restricts_user_consent_for_apps(Check): + """Check if the authorization policy restricts users from consenting apps. + + This check verifies whether the default user role permissions in Microsoft Entra + prevent users from consenting to apps that access company data on their behalf. + If such consent is disabled, the check passes. + """ + + def execute(self) -> List[CheckReportMicrosoft365]: + """Execute the check for user consent restrictions. + + Returns: + List[CheckReportMicrosoft365]: A list containing the result of the check. + """ + findings = [] + auth_policy = entra_client.authorization_policy + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=auth_policy if auth_policy else {}, + resource_name=auth_policy.name if auth_policy else "Authorization Policy", + resource_id=auth_policy.id if auth_policy else "authorizationPolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "Entra allows users to consent apps accessing company data on their behalf." + ) + + if getattr(auth_policy, "default_user_role_permissions", None) and not any( + "ManagePermissionGrantsForSelf" in policy_assigned + for policy_assigned in getattr( + auth_policy.default_user_role_permissions, + "permission_grant_policies_assigned", + ["ManagePermissionGrantsForSelf.microsoft-user-default-legacy"], + ) + ): + report.status = "PASS" + report.status_extended = "Entra does not allow users to consent apps accessing company data on their behalf." + + findings.append(report) + return findings diff --git a/tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py b/tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py new file mode 100644 index 0000000000..5dd52ebace --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py @@ -0,0 +1,150 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.microsoft365.services.entra.entra_service import ( + AuthorizationPolicy, + DefaultUserRolePermissions, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + set_mocked_microsoft365_provider, +) + + +class Test_entra_policy_restricts_user_consent_for_apps: + def test_entra_empty_policy(self): + """ + Test that the check fails when no authorization policy exists. + + This test mocks the 'entra_client.authorization_policy' as an empty dictionary. + Expected result: The check returns FAIL with the extended message indicating that + Entra allows users to consent apps accessing company data on their behalf. + """ + entra_client = mock.MagicMock + entra_client.authorization_policy = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + entra_policy_restricts_user_consent_for_apps, + ) + + check = entra_policy_restricts_user_consent_for_apps() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Entra allows users to consent apps accessing company data on their behalf." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Authorization Policy" + assert result[0].resource_id == "authorizationPolicy" + assert result[0].location == "global" + + def test_entra_policy_allows_user_consent(self): + """ + Test that the check fails when the authorization policy allows user consent. + + This test mocks the 'entra_client.authorization_policy' with a policy that includes + a permission grant policy (e.g., "ManagePermissionGrantsForSelf.microsoft-user-default-legacy") + that allows users to consent apps. + Expected result: The check returns FAIL with the extended message indicating that + Entra allows users to consent apps accessing company data on their behalf. + """ + id = str(uuid4()) + entra_client = mock.MagicMock + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + entra_policy_restricts_user_consent_for_apps, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id=id, + name="Test Policy", + description="Test Policy Description", + default_user_role_permissions=DefaultUserRolePermissions( + permission_grant_policies_assigned=[ + "ManagePermissionGrantsForSelf.microsoft-user-default-legacy" + ] + ), + ) + + check = entra_policy_restricts_user_consent_for_apps() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Entra allows users to consent apps accessing company data on their behalf." + ) + assert result[0].resource == entra_client.authorization_policy.dict() + assert result[0].resource_name == "Test Policy" + assert result[0].resource_id == id + assert result[0].location == "global" + + def test_entra_policy_restricts_user_consent(self): + """ + Test that the check passes when the authorization policy restricts user consent. + + This test mocks the 'entra_client.authorization_policy' with a policy that does not include + any permission grant policy allowing user consent (i.e., it lacks policies containing + "ManagePermissionGrantsForSelf"). + Expected result: The check returns PASS with the extended message indicating that + Entra does not allow users to consent apps accessing company data on their behalf. + """ + id = str(uuid4()) + entra_client = mock.MagicMock + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + entra_policy_restricts_user_consent_for_apps, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id=id, + name="Test Policy", + description="Test Policy Description", + default_user_role_permissions=DefaultUserRolePermissions( + permission_grant_policies_assigned=["SomeOtherPolicy"] + ), + ) + + check = entra_policy_restricts_user_consent_for_apps() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Entra does not allow users to consent apps accessing company data on their behalf." + ) + assert result[0].resource == entra_client.authorization_policy.dict() + assert result[0].resource_name == "Test Policy" + assert result[0].resource_id == id + assert result[0].location == "global" From 9312890e6af5a92895cb0bacd1ee91a83539b26e Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:45:26 +0200 Subject: [PATCH 087/359] feat(entra): add new check `entra_policy_guest_users_access_restrictions` (#7234) --- .../__init__.py | 0 ...st_users_access_restrictions.metadata.json | 30 ++++ ..._policy_guest_users_access_restrictions.py | 50 ++++++ .../services/entra/entra_service.py | 9 + ...cy_guest_users_access_restrictions_test.py | 168 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 6 + 6 files changed, 263 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py create mode 100644 tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py b/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json b/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json new file mode 100644 index 0000000000..06445080c7 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_policy_guest_users_access_restrictions", + "CheckTitle": "Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Authorization Policy", + "Description": "Limit guest user permissions.", + "Risk": "Limiting guest access ensures that guest accounts do not have permission for certain directory tasks, such as enumerating users, groups or other directory resources, and cannot be assigned to administrative roles in your directory. Guest access has three levels of restriction. 1. Guest users have the same access as members (most inclusive), 2. Guest users have limited access to properties and memberships of directory objects (default value), 3. Guest user access is restricted to properties and memberships of their own directory objects (most restrictive). The recommended option is the 3rd, most restrictive: 'Guest user access is restricted to their own directory object'.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/users/users-restrict-guest-permissions", + "Remediation": { + "Code": { + "CLI": "Update-MgPolicyAuthorizationPolicy -GuestUserRoleId ", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Entra admin center https://entra.microsoft.com/. 2. Expand Identity > External Identities and select External collaboration settings. 3. Under Guest user access, set 'Guest user access restrictions' to either 'Guest users have limited access to properties and memberships of directory objects' or 'Guest user access is restricted to properties and memberships of their own directory objects (most restrictive)'.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict guest user access in Microsoft Entra to limit the exposure of directory objects and reduce security risks.", + "Url": "https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions#member-and-guest-users" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Either of the two restrictive settings ensures compliance. The most restrictive setting prevents guests from viewing other directory objects entirely." +} diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py b/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py new file mode 100644 index 0000000000..2e431c0cd9 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py @@ -0,0 +1,50 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import AuthPolicyRoles + + +class entra_policy_guest_users_access_restrictions(Check): + """Check if guest user access is restricted to their own directory objects. + + This check verifies whether the authorization policy is configured so that guest users + are limited to accessing only the properties and memberships of their own directory objects. + """ + + def execute(self) -> List[CheckReportMicrosoft365]: + """ + Execute the guest user access restriction check. + + This method retrieves the authorization policy from the Microsoft365 Entra client, + and then checks if the 'guest_user_role_id' matches the predefined restricted role ID. + If it matches, the check passes; otherwise, it fails. + + Returns: + List[CheckReportMicrosoft365]: A list containing a single check report detailing + the status and details of the guest user access restriction. + """ + findings = [] + auth_policy = entra_client.authorization_policy + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=auth_policy if auth_policy else {}, + resource_name=auth_policy.name if auth_policy else "Authorization Policy", + resource_id=auth_policy.id if auth_policy else "authorizationPolicy", + ) + report.status = "FAIL" + report.status_extended = "Guest user access is not restricted to properties and memberships of their own directory objects" + + if ( + getattr(auth_policy, "guest_user_role_id", None) + == AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value + ) or ( + getattr(auth_policy, "guest_user_role_id", None) + == AuthPolicyRoles.GUEST_USER.value + ): + report.status = "PASS" + report.status_extended = "Guest user access is restricted to properties and memberships of their own directory objects" + + findings.append(report) + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 7dc91746ee..4acbefa940 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -1,6 +1,7 @@ from asyncio import gather, get_event_loop from enum import Enum from typing import List, Optional +from uuid import UUID from pydantic import BaseModel @@ -83,6 +84,7 @@ class Entra(Microsoft365Service): ) ], ), + guest_user_role_id=auth_policy.guest_user_role_id, ) except Exception as error: logger.error( @@ -439,6 +441,7 @@ class AuthorizationPolicy(BaseModel): name: str description: str default_user_role_permissions: Optional[DefaultUserRolePermissions] + guest_user_role_id: Optional[UUID] class Organization(BaseModel): @@ -477,3 +480,9 @@ class AdminRoles(Enum): SECURITY_ADMINISTRATOR = "194ae4cb-b126-40b2-bd5b-6091b380977d" SHAREPOINT_ADMINISTRATOR = "f28a1f50-f6e7-4571-818b-6a12f2af6b6c" USER_ADMINISTRATOR = "fe930be7-5e62-47db-91af-98c3a49a38b1" + + +class AuthPolicyRoles(Enum): + USER = UUID("a0b1b346-4d3e-4e8b-98f8-753987be4970") + GUEST_USER = UUID("10dae51f-b6af-4016-8d66-8c2a99b929b3") + GUEST_USER_ACCESS_RESTRICTED = UUID("2af84b1e-32c8-42b7-82bc-daa82404023b") diff --git a/tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py b/tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py new file mode 100644 index 0000000000..c0b8f7af37 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py @@ -0,0 +1,168 @@ +from unittest import mock + +from prowler.providers.microsoft365.services.entra.entra_service import ( + AuthorizationPolicy, + AuthPolicyRoles, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + set_mocked_microsoft365_provider, +) + + +class Test_entra_policy_guest_users_access_restrictions: + def test_no_auth_policy(self): + """ + Test when there is no authorization policy (auth_policy is None): + The check should return a report with FAIL status using default resource values. + """ + entra_client = mock.MagicMock() + entra_client.authorization_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + entra_policy_guest_users_access_restrictions, + ) + + check = entra_policy_guest_users_access_restrictions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "Guest user access is not restricted to properties and memberships of their own directory objects" + ) + assert result[0].resource_name == "Authorization Policy" + assert result[0].resource_id == "authorizationPolicy" + assert result[0].location == "global" + + def test_auth_policy_fail(self): + """ + Test when an authorization policy exists but guest_user_role_id does not match + any of the restricted roles: the check should FAIL. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + entra_policy_guest_users_access_restrictions, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy123", + name="Auth Policy Test", + description="Test policy", + guest_user_role_id=AuthPolicyRoles.USER.value, + ) + + check = entra_policy_guest_users_access_restrictions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "policy123" + assert result[0].resource_name == "Auth Policy Test" + assert result[0].location == "global" + assert result[0].status_extended == ( + "Guest user access is not restricted to properties and memberships of their own directory objects" + ) + assert result[0].resource == entra_client.authorization_policy + + def test_auth_policy_pass_restricted(self): + """ + Test when the authorization policy exists and guest_user_role_id is set to + AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED: the check should PASS. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + entra_policy_guest_users_access_restrictions, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy456", + name="Auth Policy Restricted", + description="Test policy", + guest_user_role_id=AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value, + ) + + check = entra_policy_guest_users_access_restrictions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "policy456" + assert result[0].resource_name == "Auth Policy Restricted" + assert result[0].location == "global" + assert result[0].status_extended == ( + "Guest user access is restricted to properties and memberships of their own directory objects" + ) + assert result[0].resource == entra_client.authorization_policy + + def test_auth_policy_pass_guest_user(self): + """ + Test when the authorization policy exists and guest_user_role_id is set to + AuthPolicyRoles.GUEST_USER: the check should PASS. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + entra_policy_guest_users_access_restrictions, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy789", + name="Auth Policy Guest", + description="Test policy", + guest_user_role_id=AuthPolicyRoles.GUEST_USER.value, + ) + + check = entra_policy_guest_users_access_restrictions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "policy789" + assert result[0].resource_name == "Auth Policy Guest" + assert result[0].location == "global" + assert result[0].status_extended == ( + "Guest user access is restricted to properties and memberships of their own directory objects" + ) + assert result[0].resource == entra_client.authorization_policy diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py index e9fb9fb2eb..604d7e9cf6 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py @@ -5,6 +5,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( AdminConsentPolicy, ApplicationsConditions, AuthorizationPolicy, + AuthPolicyRoles, ConditionalAccessGrantControl, ConditionalAccessPolicy, ConditionalAccessPolicyState, @@ -40,6 +41,7 @@ async def mock_entra_get_authorization_policy(_): allowed_to_read_bitlocker_keys_for_owned_device=True, allowed_to_read_other_users=True, ), + guest_user_role_id=AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value, ) @@ -147,6 +149,10 @@ class Test_Entra_Service: allowed_to_read_other_users=True, ) ) + assert ( + entra_client.authorization_policy.guest_user_role_id + == AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value + ) @patch( "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_conditional_access_policies", From f2f41c9c44fb0bd1633f82fd331e227f5d815fcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 13:29:49 +0200 Subject: [PATCH 088/359] chore(deps): bump azure-mgmt-resource from 23.2.0 to 23.3.0 (#7054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index c2a4055d0f..5c46be35d2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -562,14 +562,14 @@ msrest = ">=0.6.21" [[package]] name = "azure-mgmt-resource" -version = "23.2.0" +version = "23.3.0" description = "Microsoft Azure Resource Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_mgmt_resource-23.2.0-py3-none-any.whl", hash = "sha256:7af2bca928ecd58e57ea7f7731d245f45e9d927036d82f1d30b96baa0c26b569"}, - {file = "azure_mgmt_resource-23.2.0.tar.gz", hash = "sha256:747b750df7af23ab30e53d3f36247ab0c16de1e267d666b1a5077c39a4292529"}, + {file = "azure_mgmt_resource-23.3.0-py3-none-any.whl", hash = "sha256:ab216ee28e29db6654b989746e0c85a1181f66653929d2cb6e48fba66d9af323"}, + {file = "azure_mgmt_resource-23.3.0.tar.gz", hash = "sha256:fc4f1fd8b6aad23f8af4ed1f913df5f5c92df117449dc354fea6802a2829fea4"}, ] [package.dependencies] @@ -5336,4 +5336,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "0023fa78be2b6e67ca726e0045d7953b2e72b723d8afd80e52b733c11061b66f" +content-hash = "04a5713e73ad4eee7eb3e9f1c72504f2488374f4b134600f87c8c31aab9f8684" diff --git a/pyproject.toml b/pyproject.toml index c86f541875..1d263b0793 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ "azure-mgmt-monitor==6.0.2", "azure-mgmt-network==28.1.0", "azure-mgmt-rdbms==10.1.0", - "azure-mgmt-resource==23.2.0", + "azure-mgmt-resource==23.3.0", "azure-mgmt-search==9.1.0", "azure-mgmt-security==7.0.0", "azure-mgmt-sql==3.0.1", From ee27636f327b82ce02419ca534c95e9150f364e6 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 31 Mar 2025 13:55:48 +0200 Subject: [PATCH 089/359] fix(redshift): validation error for `Cluster.multi_az` (#7381) --- .../redshift_cluster_multi_az_enabled.py | 2 +- prowler/providers/aws/services/redshift/redshift_service.py | 4 ++-- .../redshift_cluster_multi_az_enabled_test.py | 2 +- .../providers/aws/services/redshift/redshift_service_test.py | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/prowler/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled.py b/prowler/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled.py index 63500e0360..ef06babdf9 100644 --- a/prowler/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled.py +++ b/prowler/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled.py @@ -11,7 +11,7 @@ class redshift_cluster_multi_az_enabled(Check): report.status_extended = ( f"Redshift Cluster {cluster.id} does not have Multi-AZ enabled." ) - if cluster.multi_az: + if cluster.multi_az == "Enabled": report.status = "PASS" report.status_extended = ( f"Redshift Cluster {cluster.id} has Multi-AZ enabled." diff --git a/prowler/providers/aws/services/redshift/redshift_service.py b/prowler/providers/aws/services/redshift/redshift_service.py index 03a6b92439..8284b9d05d 100644 --- a/prowler/providers/aws/services/redshift/redshift_service.py +++ b/prowler/providers/aws/services/redshift/redshift_service.py @@ -45,7 +45,7 @@ class Redshift(AWSService): "AllowVersionUpgrade", False ), encrypted=cluster.get("Encrypted", False), - multi_az=cluster.get("MultiAZ", False), + multi_az=cluster.get("MultiAZ", ""), region=regional_client.region, tags=cluster.get("Tags"), master_username=cluster.get("MasterUsername", ""), @@ -145,7 +145,7 @@ class Cluster(BaseModel): vpc_security_groups: list = [] public_access: bool = False encrypted: bool = False - multi_az: bool = False + multi_az: str = None master_username: str = None database_name: str = None endpoint_address: str = None diff --git a/tests/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled_test.py b/tests/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled_test.py index 1b2d2221c5..a32d8435db 100644 --- a/tests/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled_test.py +++ b/tests/providers/aws/services/redshift/redshift_cluster_multi_az_enabled/redshift_cluster_multi_az_enabled_test.py @@ -149,7 +149,7 @@ class Test_redshift_cluster_multi_az_enabled: ) # Moto does not pass the multi_az parameter back. - service_client.clusters[0].multi_az = 1 + service_client.clusters[0].multi_az = "Enabled" check = redshift_cluster_multi_az_enabled() result = check.execute() diff --git a/tests/providers/aws/services/redshift/redshift_service_test.py b/tests/providers/aws/services/redshift/redshift_service_test.py index ffdd6cdefa..28380ded4d 100644 --- a/tests/providers/aws/services/redshift/redshift_service_test.py +++ b/tests/providers/aws/services/redshift/redshift_service_test.py @@ -140,7 +140,8 @@ class Test_Redshift_Service: ] assert redshift.clusters[0].parameter_group_name == "default.redshift-1.0" assert redshift.clusters[0].encrypted - assert redshift.clusters[0].multi_az is False + # Moto does not pass the multi_az parameter back. + assert redshift.clusters[0].multi_az == "" assert redshift.clusters[0].master_username == "user" assert redshift.clusters[0].enhanced_vpc_routing assert redshift.clusters[0].database_name == "test" From c243110a49fd2d1c9a2375075da069ab911af40a Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 31 Mar 2025 14:53:50 +0200 Subject: [PATCH 090/359] feat(entra): add new check `entra_policy_guest_invite_only_for_admin_roles` (#7241) Co-authored-by: Sergio Garcia --- .../__init__.py | 0 ..._invite_only_for_admin_roles.metadata.json | 30 ++++ ...olicy_guest_invite_only_for_admin_roles.py | 51 ++++++ .../services/entra/entra_service.py | 9 + ..._guest_invite_only_for_admin_roles_test.py | 168 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 6 + 6 files changed, 264 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py create mode 100644 tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py b/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json b/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json new file mode 100644 index 0000000000..ffd4e74d5e --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_policy_guest_invite_only_for_admin_roles", + "CheckTitle": "Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Authorization Policy", + "Description": "Restrict invitations to users with specific administrative roles only.", + "Risk": "Restricting invitations to users with specific administrator roles ensures that only authorized accounts have access to cloud resources. This helps to maintain 'Need to Know' permissions and prevents inadvertent access to data. By default the setting Guest invite restrictions is set to Anyone in the organization can invite guest users including guests and non-admins. This would allow anyone within the organization to invite guests and non-admins to the tenant, posing a security risk.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/external-id/external-collaboration-settings-configure", + "Remediation": { + "Code": { + "CLI": "Update-MgPolicyAuthorizationPolicy -AllowInvitesFrom 'adminsAndGuestInviters'", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Entra admin center https://entra.microsoft.com/. 2. Expand Identity > External Identities and select External collaboration settings. 3. Under Guest invite settings, set 'Guest invite restrictions' to 'Only users assigned to specific admin roles can invite guest users'. 4. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict guest user invitations to only designated administrators or the Guest Inviter role to enhance security.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#guest-inviter" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "A more restrictive setting is acceptable, but the minimum requirement is limiting invitations to admins and Guest Inviters." +} diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py b/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py new file mode 100644 index 0000000000..6dfb7b5e36 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py @@ -0,0 +1,51 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import InvitationsFrom + + +class entra_policy_guest_invite_only_for_admin_roles(Check): + """Check if guest invitations are restricted to users with specific administrative roles. + + This check verifies the `guest_invite_settings` property of the authorization policy. + If the setting is set to either "adminsAndGuestInviters" or "none", guest invitations + are limited accordingly. Otherwise, they are not restricted. + """ + + def execute(self) -> List[CheckReportMicrosoft365]: + """ + Execute the guest invitation restriction check. + + Retrieves the authorization policy from the Microsoft Entra client and checks + whether the 'guest_invite_settings' is set to restrict invitations to users with + specific administrative roles only. + + Returns: + List[CheckReportMicrosoft365]: A list containing a single check report that + details the pass/fail status and description. + """ + findings = [] + auth_policy = entra_client.authorization_policy + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=auth_policy if auth_policy else {}, + resource_name=auth_policy.name if auth_policy else "Authorization Policy", + resource_id=auth_policy.id if auth_policy else "authorizationPolicy", + ) + report.status = "FAIL" + report.status_extended = "Guest invitations are not restricted to users with specific administrative roles only." + + if ( + getattr(auth_policy, "guest_invite_settings", None) + == InvitationsFrom.ADMINS_AND_GUEST_INVITERS.value + ) or ( + getattr(auth_policy, "guest_invite_settings", None) + == InvitationsFrom.NONE.value + ): + report.status = "PASS" + report.status_extended = "Guest invitations are restricted to users with specific administrative roles only." + + findings.append(report) + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 4acbefa940..6a88aad895 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -84,6 +84,7 @@ class Entra(Microsoft365Service): ) ], ), + guest_invite_settings=auth_policy.allow_invites_from, guest_user_role_id=auth_policy.guest_user_role_id, ) except Exception as error: @@ -441,6 +442,7 @@ class AuthorizationPolicy(BaseModel): name: str description: str default_user_role_permissions: Optional[DefaultUserRolePermissions] + guest_invite_settings: Optional[str] guest_user_role_id: Optional[UUID] @@ -482,6 +484,13 @@ class AdminRoles(Enum): USER_ADMINISTRATOR = "fe930be7-5e62-47db-91af-98c3a49a38b1" +class InvitationsFrom(Enum): + NONE = "none" + ADMINS_AND_GUEST_INVITERS = "adminsAndGuestInviters" + ADMINS_AND_GUEST_INVITERS_AND_MEMBERS = "adminsAndGuestInvitersAndAllMembers" + EVERYONE = "everyone" + + class AuthPolicyRoles(Enum): USER = UUID("a0b1b346-4d3e-4e8b-98f8-753987be4970") GUEST_USER = UUID("10dae51f-b6af-4016-8d66-8c2a99b929b3") diff --git a/tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py b/tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py new file mode 100644 index 0000000000..27eec2d350 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py @@ -0,0 +1,168 @@ +import mock + +from prowler.providers.microsoft365.services.entra.entra_service import ( + AuthorizationPolicy, + InvitationsFrom, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + set_mocked_microsoft365_provider, +) + + +class Test_entra_policy_guest_invite_only_for_admin_roles: + def test_no_auth_policy(self): + """ + Test when there is no authorization policy (auth_policy is None): + The check should return a report with FAIL status using default resource values. + """ + entra_client = mock.MagicMock() + entra_client.authorization_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + entra_policy_guest_invite_only_for_admin_roles, + ) + + check = entra_policy_guest_invite_only_for_admin_roles() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "Guest invitations are not restricted to users with specific administrative roles only." + ) + assert result[0].resource_name == "Authorization Policy" + assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource == {} + + def test_auth_policy_fail(self): + """ + Test when an authorization policy exists but guest_invite_settings is not set to a restricted value: + The check should FAIL. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + entra_policy_guest_invite_only_for_admin_roles, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy001", + name="Auth Policy Test", + description="Test policy", + guest_invite_settings=InvitationsFrom.EVERYONE.value, + ) + + check = entra_policy_guest_invite_only_for_admin_roles() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "Guest invitations are not restricted to users with specific administrative roles only." + ) + assert result[0].resource_id == "policy001" + assert result[0].resource_name == "Auth Policy Test" + assert result[0].location == "global" + assert result[0].resource == entra_client.authorization_policy.dict() + + def test_auth_policy_pass_admins_and_guest_inviters(self): + """ + Test when the authorization policy exists and guest_invite_settings is set to + InvitationsFrom.ADMINS_AND_GUEST_INVITERS: the check should PASS. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + entra_policy_guest_invite_only_for_admin_roles, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy002", + name="Auth Policy Restricted", + description="Test policy", + guest_invite_settings=InvitationsFrom.ADMINS_AND_GUEST_INVITERS.value, + ) + + check = entra_policy_guest_invite_only_for_admin_roles() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "Guest invitations are restricted to users with specific administrative roles only." + ) + assert result[0].resource_id == "policy002" + assert result[0].resource_name == "Auth Policy Restricted" + assert result[0].location == "global" + assert result[0].resource == entra_client.authorization_policy.dict() + + def test_auth_policy_pass_none(self): + """ + Test when the authorization policy exists and guest_invite_settings is set to + InvitationsFrom.NONE: the check should PASS. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + entra_policy_guest_invite_only_for_admin_roles, + ) + + entra_client.authorization_policy = AuthorizationPolicy( + id="policy003", + name="Auth Policy Restricted None", + description="Test policy", + guest_invite_settings=InvitationsFrom.NONE.value, + ) + + check = entra_policy_guest_invite_only_for_admin_roles() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "Guest invitations are restricted to users with specific administrative roles only." + ) + assert result[0].resource_id == "policy003" + assert result[0].resource_name == "Auth Policy Restricted None" + assert result[0].location == "global" + assert result[0].resource == entra_client.authorization_policy.dict() diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py index 604d7e9cf6..df87759903 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py @@ -14,6 +14,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( Entra, GrantControlOperator, GrantControls, + InvitationsFrom, Organization, PersistentBrowser, SessionControls, @@ -41,6 +42,7 @@ async def mock_entra_get_authorization_policy(_): allowed_to_read_bitlocker_keys_for_owned_device=True, allowed_to_read_other_users=True, ), + guest_invite_settings=InvitationsFrom.ADMINS_AND_GUEST_INVITERS.value, guest_user_role_id=AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value, ) @@ -149,6 +151,10 @@ class Test_Entra_Service: allowed_to_read_other_users=True, ) ) + assert ( + entra_client.authorization_policy.guest_invite_settings + == InvitationsFrom.ADMINS_AND_GUEST_INVITERS.value + ) assert ( entra_client.authorization_policy.guest_user_role_id == AuthPolicyRoles.GUEST_USER_ACCESS_RESTRICTED.value From b8ce09ec34055783d406ebadf4059b698b3bfd4e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 31 Mar 2025 17:50:51 +0200 Subject: [PATCH 091/359] fix(entra): check name and logic of `entra_admin_users_have_mfa_enabled` (#7230) --- .../__init__.py | 0 ..._portals_access_restriction.metadata.json} | 5 +- ...entra_admin_portals_access_restriction.py} | 2 +- .../__init__.py | 0 ...tra_admin_users_mfa_enabled.metadata.json} | 5 +- .../entra_admin_users_mfa_enabled.py} | 10 +- ..._admin_portals_access_restriction_test.py} | 34 +-- .../entra_admin_users_mfa_enabled_test.py} | 205 +++++++++++++++--- 8 files changed, 207 insertions(+), 54 deletions(-) rename prowler/providers/microsoft365/services/entra/{entra_admin_mfa_enabled_for_administrative_roles => entra_admin_portals_access_restriction}/__init__.py (100%) rename prowler/providers/microsoft365/services/entra/{entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.metadata.json => entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json} (94%) rename prowler/providers/microsoft365/services/entra/{entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.py => entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py} (98%) rename prowler/providers/microsoft365/services/entra/{entra_admin_portals_role_limited_access => entra_admin_users_mfa_enabled}/__init__.py (100%) rename prowler/providers/microsoft365/services/entra/{entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.metadata.json => entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json} (93%) rename prowler/providers/microsoft365/services/entra/{entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.py => entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py} (91%) rename tests/providers/microsoft365/services/entra/{entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py => entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py} (89%) rename tests/providers/microsoft365/services/entra/{entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py => entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py} (71%) diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/__init__.py b/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/__init__.py rename to prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.metadata.json b/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json similarity index 94% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.metadata.json rename to prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json index 87493e9bd0..41ba6ba9ce 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.metadata.json +++ b/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json @@ -1,7 +1,10 @@ { "Provider": "microsoft365", - "CheckID": "entra_admin_portals_role_limited_access", + "CheckID": "entra_admin_portals_access_restriction", "CheckTitle": "Ensure that only administrative roles have access to Microsoft Admin Portals", + "CheckAliases": [ + "entra_admin_portals_role_limited_access" + ], "CheckType": [], "ServiceName": "entra", "SubServiceName": "", diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.py b/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.py rename to prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py index 0b0b08aaac..a8f744ec4a 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access.py +++ b/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py @@ -7,7 +7,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( ) -class entra_admin_portals_role_limited_access(Check): +class entra_admin_portals_access_restriction(Check): """Check if Conditional Access policies deny access to the Microsoft 365 admin center for users with limited access roles. This check ensures that Conditional Access policies are in place to deny access to the Microsoft 365 admin center for users with limited access roles. diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/__init__.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/__init__.py rename to prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.metadata.json b/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json similarity index 93% rename from prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.metadata.json rename to prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json index 942e1a3c97..63f312be10 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.metadata.json +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json @@ -1,7 +1,10 @@ { "Provider": "microsoft365", - "CheckID": "entra_admin_mfa_enabled_for_administrative_roles", + "CheckID": "entra_admin_users_mfa_enabled", "CheckTitle": "Ensure multifactor authentication is enabled for all users in administrative roles.", + "CheckAliases": [ + "entra_admin_mfa_enabled_for_administrative_roles" + ], "CheckType": [], "ServiceName": "entra", "SubServiceName": "", diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py similarity index 91% rename from prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.py rename to prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py index d69276f135..e668ffd11a 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles.py +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py @@ -9,7 +9,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( ) -class entra_admin_mfa_enabled_for_administrative_roles(Check): +class entra_admin_users_mfa_enabled(Check): """ Ensure multifactor authentication is enabled for all users in administrative roles. @@ -68,13 +68,13 @@ class entra_admin_mfa_enabled_for_administrative_roles(Check): resource_name=policy.display_name, resource_id=policy.id, ) - report.status = "PASS" - report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces MFA for administrative roles." - if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING: report.status = "FAIL" report.status_extended = f"Conditional Access Policy '{policy.display_name}' only reports MFA for administrative roles but does not enforce it." - break + else: + report.status = "PASS" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces MFA for administrative roles." + break findings.append(report) return findings diff --git a/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py b/tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py similarity index 89% rename from tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py rename to tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py index 71eaaa4dd4..23bed663b9 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_portals_role_limited_access/entra_admin_portals_role_limited_access_test.py +++ b/tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py @@ -20,7 +20,7 @@ from tests.providers.microsoft365.microsoft365_fixtures import ( ) -class Test_entra_admin_portals_role_limited_access: +class Test_entra_admin_portals_access_restriction: def test_entra_no_conditional_access_policies(self): entra_client = mock.MagicMock entra_client.audited_tenant = "audited_tenant" @@ -31,17 +31,17 @@ class Test_entra_admin_portals_role_limited_access: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import ( - entra_admin_portals_role_limited_access, + from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + entra_admin_portals_access_restriction, ) entra_client.conditional_access_policies = {} - check = entra_admin_portals_role_limited_access() + check = entra_admin_portals_access_restriction() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" @@ -66,12 +66,12 @@ class Test_entra_admin_portals_role_limited_access: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import ( - entra_admin_portals_role_limited_access, + from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + entra_admin_portals_access_restriction, ) from prowler.providers.microsoft365.services.entra.entra_service import ( ConditionalAccessPolicy, @@ -114,7 +114,7 @@ class Test_entra_admin_portals_role_limited_access: ) } - check = entra_admin_portals_role_limited_access() + check = entra_admin_portals_access_restriction() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" @@ -140,12 +140,12 @@ class Test_entra_admin_portals_role_limited_access: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import ( - entra_admin_portals_role_limited_access, + from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + entra_admin_portals_access_restriction, ) from prowler.providers.microsoft365.services.entra.entra_service import ( ConditionalAccessPolicy, @@ -189,7 +189,7 @@ class Test_entra_admin_portals_role_limited_access: ) } - check = entra_admin_portals_role_limited_access() + check = entra_admin_portals_access_restriction() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" @@ -218,12 +218,12 @@ class Test_entra_admin_portals_role_limited_access: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import ( - entra_admin_portals_role_limited_access, + from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + entra_admin_portals_access_restriction, ) from prowler.providers.microsoft365.services.entra.entra_service import ( ConditionalAccessPolicy, @@ -267,7 +267,7 @@ class Test_entra_admin_portals_role_limited_access: ) } - check = entra_admin_portals_role_limited_access() + check = entra_admin_portals_access_restriction() result = check.execute() assert len(result) == 1 assert result[0].status == "PASS" diff --git a/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py b/tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py similarity index 71% rename from tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py rename to tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py index 4492ac809c..1a628de808 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_mfa_enabled_for_administrative_roles/entra_admin_mfa_enabled_for_administrative_roles_test.py +++ b/tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py @@ -21,7 +21,7 @@ from tests.providers.microsoft365.microsoft365_fixtures import ( ) -class Test_entra_admin_mfa_enabled_for_administrative_roles: +class Test_entra_admin_users_mfa_enabled: def test_no_conditional_access_policies(self): """No conditional access policies configured: expected FAIL.""" entra_client = mock.MagicMock @@ -34,17 +34,17 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = {} - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -70,12 +70,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -116,7 +116,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -146,12 +146,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -192,7 +192,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -222,12 +222,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -268,7 +268,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -303,12 +303,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -349,7 +349,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -382,12 +382,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -444,7 +444,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -477,12 +477,12 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: return_value=set_mocked_microsoft365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles.entra_client", + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_mfa_enabled_for_administrative_roles.entra_admin_mfa_enabled_for_administrative_roles import ( - entra_admin_mfa_enabled_for_administrative_roles, + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, ) entra_client.conditional_access_policies = { @@ -538,7 +538,7 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: ) } - check = entra_admin_mfa_enabled_for_administrative_roles() + check = entra_admin_users_mfa_enabled() result = check.execute() assert len(result) == 1 @@ -548,3 +548,150 @@ class Test_entra_admin_mfa_enabled_for_administrative_roles: assert result[0].resource == {} assert result[0].resource_name == "Conditional Access Policies" assert result[0].resource_id == "conditionalAccessPolicies" + + def test_policy_invalid_and_valid_policy(self): + """ + Valid policy: + - State enabled (ENABLED) + - Applies to administrative roles + - Application conditions include "All" + - MFA is configured in grant_controls + + Expected PASS. + """ + policy_id = str(uuid4()) + policy_id2 = str(uuid4()) + display_name = "Valid MFA Policy" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + entra_admin_users_mfa_enabled, + ) + + entra_client.conditional_access_policies = { + policy_id: ConditionalAccessPolicy( + id=policy_id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=[], + excluded_users=[], + included_roles=[ + "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3", + "c4e39bd9-1100-46d3-8c65-fb160da0071f", + "b0f54661-2d74-4c50-afa3-1ec803f12efe", + "158c047a-c907-4556-b7ef-446551a6b5f7", + "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", + "29232cdf-9323-42fd-ade2-1d097af3e4de", + "62e90394-69f5-4237-9190-012177145e10", + "f2ef992c-3afb-46b9-b7cf-a126ee74c451", + "729827e3-9c14-49f7-bb1b-9608f156bbb8", + "966707d0-3269-4727-9be2-8c3a10f19b9d", + "7be44c8a-adaf-4e2a-84d6-ab2649e08a13", + "e8611ab8-c189-46e8-94e1-60213ab1f814", + "194ae4cb-b126-40b2-bd5b-6091b380977d", + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", + "fe930be7-5e62-47db-91af-98c3a49a38b1", + ], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.MFA], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING, + ), + policy_id2: ConditionalAccessPolicy( + id=policy_id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=[], + excluded_users=[], + included_roles=[ + "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3", + "c4e39bd9-1100-46d3-8c65-fb160da0071f", + "b0f54661-2d74-4c50-afa3-1ec803f12efe", + "158c047a-c907-4556-b7ef-446551a6b5f7", + "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", + "29232cdf-9323-42fd-ade2-1d097af3e4de", + "62e90394-69f5-4237-9190-012177145e10", + "f2ef992c-3afb-46b9-b7cf-a126ee74c451", + "729827e3-9c14-49f7-bb1b-9608f156bbb8", + "966707d0-3269-4727-9be2-8c3a10f19b9d", + "7be44c8a-adaf-4e2a-84d6-ab2649e08a13", + "e8611ab8-c189-46e8-94e1-60213ab1f814", + "194ae4cb-b126-40b2-bd5b-6091b380977d", + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", + "fe930be7-5e62-47db-91af-98c3a49a38b1", + ], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.MFA], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED, + ), + } + + check = entra_admin_users_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + expected_status_extended = f"Conditional Access Policy '{display_name}' enforces MFA for administrative roles." + assert result[0].status_extended == expected_status_extended + assert result[0].resource == entra_client.conditional_access_policies + assert result[0].resource_name == display_name + assert result[0].resource_id == policy_id From 7ba99f22cd5282388bda94ba4417f7b26a1daf9b Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 31 Mar 2025 17:52:28 +0200 Subject: [PATCH 092/359] feat(entra): add new check `entra_admin_users_phishing_resistant_mfa_enabled` (#7211) Co-authored-by: Sergio Garcia --- .../__init__.py | 0 ...ishing_resistant_mfa_enabled.metadata.json | 30 ++ ...in_users_phishing_resistant_mfa_enabled.py | 67 ++++ .../services/entra/entra_service.py | 16 + ...ers_phishing_resistant_mfa_enabled_test.py | 338 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 3 + 6 files changed, 454 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py create mode 100644 tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json b/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json new file mode 100644 index 0000000000..3aacb2c1ac --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_admin_users_phishing_resistant_mfa_enabled", + "CheckTitle": "Ensure phishing-resistant MFA strength is required for all administrator accounts", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Conditional Access Policy", + "Description": "Ensure ", + "Risk": "Administrators using weaker MFA methods, such as SMS or push notifications, are vulnerable to phishing attacks and MFA fatigue attacks. Attackers can intercept codes or trick users into approving fraudulent authentication requests, leading to unauthorized access to critical systems.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-admin-phish-resistant-mfa", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com. 2. Click expand Protection > Conditional Access select Policies. 3. Click New policy. Under Users include Select users and groups and check Directory roles. At a minimum, include the directory roles listed below in this section of the document. Under Target resources include All cloud apps and do not create any exclusions. Under Grant select Grant Access and check Require authentication strength and set Phishing-resistant MFA in the dropdown box. Click Select. 4. Under Enable policy set it to Report Only until the organization is ready to enable it. 5. Click Create.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Require phishing-resistant MFA strength for all administrator accounts through Conditional Access policies. Enforce the use of FIDO2 security keys, Windows Hello for Business, or certificate-based authentication. Ensure administrators are pre-registered for these methods before enforcement to prevent lockouts. Maintain a break-glass account exempt from this policy for emergency access.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-admin-phish-resistant-mfa#create-a-conditional-access-policy" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py new file mode 100644 index 0000000000..97022161f7 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py @@ -0,0 +1,67 @@ +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import ( + AdminRoles, + AuthenticationStrength, + ConditionalAccessPolicyState, +) + + +class entra_admin_users_phishing_resistant_mfa_enabled(Check): + """Check if Conditional Access policies require Phishing-resistant MFA strength for admin users.""" + + def execute(self) -> list[CheckReportMicrosoft365]: + """Execute the check to ensure that Conditional Access policies require Phishing-resistant MFA strength for admin users. + + Returns: + list[CheckReportMicrosoft365]: A list containing the results of the check. + """ + findings = [] + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource={}, + resource_name="Conditional Access Policies", + resource_id="conditionalAccessPolicies", + ) + report.status = "FAIL" + report.status_extended = "No Conditional Access Policy requires Phishing-resistant MFA strength for admin users." + + for policy in entra_client.conditional_access_policies.values(): + if policy.state == ConditionalAccessPolicyState.DISABLED: + continue + + if not ( + {role.value for role in AdminRoles}.issuperset( + policy.conditions.user_conditions.included_roles + ) + ): + continue + + if ( + "All" + not in policy.conditions.application_conditions.included_applications + or policy.conditions.application_conditions.excluded_applications != [] + ): + continue + + if ( + policy.grant_controls.authentication_strength is not None + and policy.grant_controls.authentication_strength + == AuthenticationStrength.PHISHING_RESISTANT_MFA + ): + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.display_name, + resource_id=policy.id, + ) + if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING: + report.status = "FAIL" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports Phishing-resistant MFA strength for admin users but does not require it." + else: + report.status = "PASS" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' requires Phishing-resistant MFA strength for admin users." + break + + findings.append(report) + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 6a88aad895..752f1619e8 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -214,6 +214,15 @@ class Entra(Microsoft365Service): getattr(policy.grant_controls, "operator", "AND") ) ), + authentication_strength=( + AuthenticationStrength( + policy.grant_controls.authentication_strength.display_name + ) + if policy.grant_controls is not None + and policy.grant_controls.authentication_strength + is not None + else None + ), ), session_controls=SessionControls( persistent_browser=PersistentBrowser( @@ -413,9 +422,16 @@ class GrantControlOperator(Enum): OR = "OR" +class AuthenticationStrength(Enum): + MFA = "Multifactor authentication" + PASSWORDLESS_MFA = "Passwordless MFA" + PHISHING_RESISTANT_MFA = "Phishing-resistant MFA" + + class GrantControls(BaseModel): built_in_controls: List[ConditionalAccessGrantControl] operator: GrantControlOperator + authentication_strength: Optional[AuthenticationStrength] class ConditionalAccessPolicy(BaseModel): diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py b/tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py new file mode 100644 index 0000000000..7d6c5987b1 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py @@ -0,0 +1,338 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.microsoft365.services.entra.entra_service import ( + ApplicationsConditions, + AuthenticationStrength, + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, + Conditions, + GrantControlOperator, + GrantControls, + PersistentBrowser, + SessionControls, + SignInFrequency, + SignInFrequencyInterval, + UsersConditions, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + DOMAIN, + set_mocked_microsoft365_provider, +) + + +class Test_entra_admin_users_phishing_resistant_mfa_enabled: + def test_entra_no_conditional_access_policies(self): + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + entra_admin_users_phishing_resistant_mfa_enabled, + ) + + entra_client.conditional_access_policies = {} + + check = entra_admin_users_phishing_resistant_mfa_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy requires Phishing-resistant MFA strength for admin users." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_phishing_resistant_mfa_strength_disabled(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + entra_admin_users_phishing_resistant_mfa_enabled, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[ + "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3", + "c4e39bd9-1100-46d3-8c65-fb160da0071f", + "b0f54661-2d74-4c50-afa3-1ec803f12efe", + "158c047a-c907-4556-b7ef-446551a6b5f7", + "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", + "29232cdf-9323-42fd-ade2-1d097af3e4de", + "62e90394-69f5-4237-9190-012177145e10", + "f2ef992c-3afb-46b9-b7cf-a126ee74c451", + "729827e3-9c14-49f7-bb1b-9608f156bbb8", + "966707d0-3269-4727-9be2-8c3a10f19b9d", + "7be44c8a-adaf-4e2a-84d6-ab2649e08a13", + "e8611ab8-c189-46e8-94e1-60213ab1f814", + "194ae4cb-b126-40b2-bd5b-6091b380977d", + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", + "fe930be7-5e62-47db-91af-98c3a49a38b1", + ], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.BLOCK], + operator=GrantControlOperator.AND, + authentication_strength=AuthenticationStrength.PHISHING_RESISTANT_MFA, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.DISABLED, + ) + } + + check = entra_admin_users_phishing_resistant_mfa_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy requires Phishing-resistant MFA strength for admin users." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_phishing_resistant_mfa_strength_enabled_for_reporting(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + entra_admin_users_phishing_resistant_mfa_enabled, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[ + "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3", + "c4e39bd9-1100-46d3-8c65-fb160da0071f", + "b0f54661-2d74-4c50-afa3-1ec803f12efe", + "158c047a-c907-4556-b7ef-446551a6b5f7", + "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", + "29232cdf-9323-42fd-ade2-1d097af3e4de", + "62e90394-69f5-4237-9190-012177145e10", + "f2ef992c-3afb-46b9-b7cf-a126ee74c451", + "729827e3-9c14-49f7-bb1b-9608f156bbb8", + "966707d0-3269-4727-9be2-8c3a10f19b9d", + "7be44c8a-adaf-4e2a-84d6-ab2649e08a13", + "e8611ab8-c189-46e8-94e1-60213ab1f814", + "194ae4cb-b126-40b2-bd5b-6091b380977d", + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", + "fe930be7-5e62-47db-91af-98c3a49a38b1", + ], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.BLOCK], + operator=GrantControlOperator.AND, + authentication_strength=AuthenticationStrength.PHISHING_RESISTANT_MFA, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING, + ) + } + + check = entra_admin_users_phishing_resistant_mfa_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' reports Phishing-resistant MFA strength for admin users but does not require it." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" + + def test_entra_phishing_resistant_mfa_strength_enabled(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + entra_admin_users_phishing_resistant_mfa_enabled, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[ + "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3", + "c4e39bd9-1100-46d3-8c65-fb160da0071f", + "b0f54661-2d74-4c50-afa3-1ec803f12efe", + "158c047a-c907-4556-b7ef-446551a6b5f7", + "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9", + "29232cdf-9323-42fd-ade2-1d097af3e4de", + "62e90394-69f5-4237-9190-012177145e10", + "f2ef992c-3afb-46b9-b7cf-a126ee74c451", + "729827e3-9c14-49f7-bb1b-9608f156bbb8", + "966707d0-3269-4727-9be2-8c3a10f19b9d", + "7be44c8a-adaf-4e2a-84d6-ab2649e08a13", + "e8611ab8-c189-46e8-94e1-60213ab1f814", + "194ae4cb-b126-40b2-bd5b-6091b380977d", + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c", + "fe930be7-5e62-47db-91af-98c3a49a38b1", + ], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.BLOCK], + operator=GrantControlOperator.AND, + authentication_strength=AuthenticationStrength.PHISHING_RESISTANT_MFA, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED, + ) + } + + check = entra_admin_users_phishing_resistant_mfa_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' requires Phishing-resistant MFA strength for admin users." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py index df87759903..19a027e60c 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py @@ -4,6 +4,7 @@ from prowler.providers.microsoft365.models import Microsoft365IdentityInfo from prowler.providers.microsoft365.services.entra.entra_service import ( AdminConsentPolicy, ApplicationsConditions, + AuthenticationStrength, AuthorizationPolicy, AuthPolicyRoles, ConditionalAccessGrantControl, @@ -70,6 +71,7 @@ async def mock_entra_get_conditional_access_policies(_): grant_controls=GrantControls( built_in_controls=[ConditionalAccessGrantControl.BLOCK], operator=GrantControlOperator.OR, + authentication_strength=AuthenticationStrength.PHISHING_RESISTANT_MFA, ), session_controls=SessionControls( persistent_browser=PersistentBrowser( @@ -188,6 +190,7 @@ class Test_Entra_Service: grant_controls=GrantControls( built_in_controls=[ConditionalAccessGrantControl.BLOCK], operator=GrantControlOperator.OR, + authentication_strength=AuthenticationStrength.PHISHING_RESISTANT_MFA, ), session_controls=SessionControls( persistent_browser=PersistentBrowser( From a7ed610da9858125c6666b88eacf35cc97143f8f Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 31 Mar 2025 17:54:52 +0200 Subject: [PATCH 093/359] feat(entra): add new check `entra_users_mfa_enabled` (#7228) --- .../entra/entra_users_mfa_enabled/__init__.py | 0 .../entra_users_mfa_enabled.metadata.json | 30 ++ .../entra_users_mfa_enabled.py | 77 +++++ .../entra_users_mfa_enabled_test.py | 288 ++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py create mode 100644 tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/__init__.py b/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json b/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json new file mode 100644 index 0000000000..75f82197c5 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_users_mfa_enabled", + "CheckTitle": "Ensure multifactor authentication is enabled for all users.", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Conditional Access Policy", + "Description": "Ensure that multifactor authentication (MFA) is enabled for all users to enhance security and reduce the risk of unauthorized access.", + "Risk": "Without multifactor authentication (MFA), users are at a higher risk of account compromise due to credential theft, phishing, or brute-force attacks. A single-factor authentication method, such as passwords, is often insufficient to protect against modern cyber threats.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/authentication/tutorial-enable-azure-mfa", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com. 2. Click expand Protection > Conditional Access select Policies. 3. Click New policy. Under Users include All users (and do not exclude any user). Under Target resources include All cloud apps and do not create any exclusions. Under Grant select Grant Access and check Require multifactor authentication. Click Select at the bottom of the pane. 4. Under Enable policy set it to Report Only until the organization is ready to enable it. 5. Click Create.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable multifactor authentication for all users in the Microsoft 365 tenant. Ensure users register at least one strong second-factor authentication method, such as Microsoft Authenticator, SMS codes, or phone calls. Educate users on the importance of MFA and provide clear instructions for enrollment to minimize disruptions.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/authentication/tutorial-enable-azure-mfa" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py b/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py new file mode 100644 index 0000000000..8159c3ebc4 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py @@ -0,0 +1,77 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, +) + + +class entra_users_mfa_enabled(Check): + """ + Ensure multifactor authentication is enabled for all users. + + This check verifies that at least one Conditional Access Policy in Microsoft Entra, which is in an enabled state, + requires multifactor authentication for all users. + + The check fails if no enabled policy is found that requires MFA for all users. + """ + + def execute(self) -> List[CheckReportMicrosoft365]: + """ + Execute the admin MFA requirement check for all users. + + Iterates over the Conditional Access Policies retrieved from the Entra client and generates a report + indicating whether MFA is enforced for users in all users. + + Returns: + List[CheckReportMicrosoft365]: A list containing a single report with the result of the check. + """ + findings = [] + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource={}, + resource_name="Conditional Access Policies", + resource_id="conditionalAccessPolicies", + ) + + report.status = "FAIL" + report.status_extended = ( + "No Conditional Access Policy enforces MFA for all users." + ) + + for policy in entra_client.conditional_access_policies.values(): + if policy.state == ConditionalAccessPolicyState.DISABLED: + continue + + if "All" not in policy.conditions.user_conditions.included_users: + continue + + if ( + "All" + not in policy.conditions.application_conditions.included_applications + ): + continue + + if ( + ConditionalAccessGrantControl.MFA + in policy.grant_controls.built_in_controls + ): + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=entra_client.conditional_access_policies, + resource_name=policy.display_name, + resource_id=policy.id, + ) + if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING: + report.status = "FAIL" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports MFA requirement for all users but does not enforce it." + else: + report.status = "PASS" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces MFA for all users." + break + + findings.append(report) + return findings diff --git a/tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py b/tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py new file mode 100644 index 0000000000..7552cea160 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py @@ -0,0 +1,288 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.microsoft365.services.entra.entra_service import ( + ApplicationsConditions, + ConditionalAccessGrantControl, + ConditionalAccessPolicy, + ConditionalAccessPolicyState, + Conditions, + GrantControlOperator, + GrantControls, + PersistentBrowser, + SessionControls, + SignInFrequency, + SignInFrequencyInterval, + UsersConditions, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + DOMAIN, + set_mocked_microsoft365_provider, +) + + +class Test_entra_users_mfa_enabled: + def test_no_conditional_access_policies(self): + """No conditional access policies configured: expected FAIL.""" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + entra_users_mfa_enabled, + ) + + entra_client.conditional_access_policies = {} + + check = entra_users_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy enforces MFA for all users." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + + def test_policy_disabled(self): + """Policy in DISABLED state: expected to be ignored and return FAIL.""" + policy_id = str(uuid4()) + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + entra_users_mfa_enabled, + ) + + entra_client.conditional_access_policies = { + policy_id: ConditionalAccessPolicy( + id=policy_id, + display_name="Disabled Policy", + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.MFA], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.DISABLED, + ) + } + + check = entra_users_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy enforces MFA for all users." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + + def test_policy_mfa_enabled_for_report(self): + """ + Valid policy: + - State enabled for reporting only + - Applies to administrative roles via 'All' in included_users + - Application conditions include "All" + - MFA is configured in grant_controls + + Expected FAIL due to is only for reporting. + """ + policy_id = str(uuid4()) + display_name = "Invalid MFA Policy" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + entra_users_mfa_enabled, + ) + + entra_client.conditional_access_policies = { + policy_id: ConditionalAccessPolicy( + id=policy_id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.MFA], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING, + ) + } + + check = entra_users_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + expected_status_extended = f"Conditional Access Policy '{display_name}' reports MFA requirement for all users but does not enforce it." + assert result[0].status_extended == expected_status_extended + assert result[0].resource == entra_client.conditional_access_policies + assert result[0].resource_name == display_name + assert result[0].resource_id == policy_id + + def test_policy_valid_through_roles(self): + """ + Valid policy: + - State enabled (ENABLED) + - Applies to administrative roles + - Application conditions include "All" + - MFA is configured in grant_controls + + Expected PASS. + """ + policy_id = str(uuid4()) + display_name = "Valid MFA Policy" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + entra_users_mfa_enabled, + ) + + entra_client.conditional_access_policies = { + policy_id: ConditionalAccessPolicy( + id=policy_id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + ), + grant_controls=GrantControls( + built_in_controls=[ConditionalAccessGrantControl.MFA], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED, + ) + } + + check = entra_users_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + expected_status_extended = f"Conditional Access Policy '{display_name}' enforces MFA for all users." + assert result[0].status_extended == expected_status_extended + assert result[0].resource == entra_client.conditional_access_policies + assert result[0].resource_name == display_name + assert result[0].resource_id == policy_id From 024f1425dfca927956ff1968bf2ed321530b85f2 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 31 Mar 2025 18:12:26 +0200 Subject: [PATCH 094/359] feat(entra): add new check `entra_legacy_authentication_blocked` (#7240) --- .../__init__.py | 0 ...egacy_authentication_blocked.metadata.json | 30 ++ .../entra_legacy_authentication_blocked.py | 73 +++++ .../services/entra/entra_service.py | 17 + ...ntra_legacy_authentication_blocked_test.py | 308 ++++++++++++++++++ 5 files changed, 428 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py create mode 100644 tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/__init__.py b/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json b/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json new file mode 100644 index 0000000000..31ab36f686 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_legacy_authentication_blocked", + "CheckTitle": "Ensure that Conditional Access policy blocks legacy authentication", + "CheckType": [], + "ServiceName": "critical", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Conditional Access Policy", + "Description": "Ensure that Conditional Access policy blocks legacy authentication in Microsoft Entra ID to enforce modern authentication methods and protect against credential-stuffing and brute-force attacks.", + "Risk": "Legacy authentication protocols do not support MFA, making them vulnerable to credential-stuffing and brute-force attacks. Attackers commonly exploit these protocols to bypass security controls and gain unauthorized access.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-block-legacy-authentication", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com. 2. Click expand Protection > Conditional Access select Policies. 3. Create a new policy by selecting New policy. Under Users include All users. Under Target resources include All cloud apps and do not create any exclusions. Under Conditions select Client apps and check the boxes for Exchange ActiveSync clients and Other clients. Under Grant select Block Access. Click Select. 4. Set the policy On and click Create.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enforce Conditional Access policies to block legacy authentication across all users in Microsoft Entra ID. Ensure all applications and devices use modern authentication methods such as OAuth 2.0. For necessary exceptions (e.g., multifunction printers), configure secure alternatives following Microsoft's mail flow best practices.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-block-legacy-authentication" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py b/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py new file mode 100644 index 0000000000..ee14720618 --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py @@ -0,0 +1,73 @@ +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import ( + ClientAppType, + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, +) + + +class entra_legacy_authentication_blocked(Check): + """Check if at least one Conditional Access policy blocks legacy authentication. + + This check ensures that at least one Conditional Access policy blocks legacy authentication. + """ + + def execute(self) -> list[CheckReportMicrosoft365]: + """Execute the check to ensure that at least one Conditional Access policy blocks legacy authentication. + + Returns: + list[CheckReportMicrosoft365]: A list containing the results of the check. + """ + findings = [] + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource={}, + resource_name="Conditional Access Policies", + resource_id="conditionalAccessPolicies", + ) + report.status = "FAIL" + report.status_extended = ( + "No Conditional Access Policy blocks legacy authentication." + ) + + for policy in entra_client.conditional_access_policies.values(): + if policy.state == ConditionalAccessPolicyState.DISABLED: + continue + + if "All" not in policy.conditions.user_conditions.included_users: + continue + + if ( + "All" + not in policy.conditions.application_conditions.included_applications + ): + continue + + if ( + ClientAppType.EXCHANGE_ACTIVE_SYNC + not in policy.conditions.client_app_types + or ClientAppType.OTHER_CLIENTS not in policy.conditions.client_app_types + ): + continue + + if ( + ConditionalAccessGrantControl.BLOCK + in policy.grant_controls.built_in_controls + ): + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.display_name, + resource_id=policy.id, + ) + if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING: + report.status = "FAIL" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports legacy authentication but does not block it." + else: + report.status = "PASS" + report.status_extended = f"Conditional Access Policy '{policy.display_name}' blocks legacy authentication." + break + + findings.append(report) + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 752f1619e8..557077f3bc 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -181,6 +181,14 @@ class Entra(Microsoft365Service): ) ], ), + client_app_types=[ + ClientAppType(client_app_type) + for client_app_type in getattr( + policy.conditions, + "client_app_types", + [], + ) + ], user_risk_levels=[ RiskLevel(risk_level) for risk_level in getattr( @@ -376,9 +384,18 @@ class RiskLevel(Enum): NO_RISK = "none" +class ClientAppType(Enum): + ALL = "all" + BROWSER = "browser" + MOBILE_APPS_AND_DESKTOP_CLIENTS = "mobileAppsAndDesktopClients" + EXCHANGE_ACTIVE_SYNC = "exchangeActiveSync" + OTHER_CLIENTS = "other" + + class Conditions(BaseModel): application_conditions: Optional[ApplicationsConditions] user_conditions: Optional[UsersConditions] + client_app_types: Optional[List[ClientAppType]] user_risk_levels: List[RiskLevel] = [] sign_in_risk_levels: List[RiskLevel] = [] diff --git a/tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py b/tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py new file mode 100644 index 0000000000..1b45102d23 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py @@ -0,0 +1,308 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.microsoft365.services.entra.entra_service import ( + ApplicationsConditions, + ClientAppType, + ConditionalAccessGrantControl, + ConditionalAccessPolicyState, + Conditions, + GrantControlOperator, + GrantControls, + PersistentBrowser, + SessionControls, + SignInFrequency, + SignInFrequencyInterval, + UsersConditions, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + DOMAIN, + set_mocked_microsoft365_provider, +) + + +class Test_entra_legacy_authentication_blocked: + def test_entra_no_conditional_access_policies(self): + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + entra_legacy_authentication_blocked, + ) + + entra_client.conditional_access_policies = {} + + check = entra_legacy_authentication_blocked() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy blocks legacy authentication." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_block_legacy_authentication_disabled(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + entra_legacy_authentication_blocked, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + client_app_types=[ + ClientAppType.EXCHANGE_ACTIVE_SYNC, + ClientAppType.OTHER_CLIENTS, + ], + user_risk_levels=[], + ), + grant_controls=GrantControls( + built_in_controls=[ + ConditionalAccessGrantControl.BLOCK, + ], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.DISABLED, + ) + } + + check = entra_legacy_authentication_blocked() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "No Conditional Access Policy blocks legacy authentication." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Conditional Access Policies" + assert result[0].resource_id == "conditionalAccessPolicies" + assert result[0].location == "global" + + def test_entra_block_legacy_authentication_enabled_for_reporting(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + entra_legacy_authentication_blocked, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + client_app_types=[ + ClientAppType.EXCHANGE_ACTIVE_SYNC, + ClientAppType.OTHER_CLIENTS, + ], + user_risk_levels=[], + ), + grant_controls=GrantControls( + built_in_controls=[ + ConditionalAccessGrantControl.BLOCK, + ], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING, + ) + } + + check = entra_legacy_authentication_blocked() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' reports legacy authentication but does not block it." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" + + def test_entra_block_legacy_authentication_enabled(self): + id = str(uuid4()) + display_name = "Test" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + entra_legacy_authentication_blocked, + ) + from prowler.providers.microsoft365.services.entra.entra_service import ( + ConditionalAccessPolicy, + ) + + entra_client.conditional_access_policies = { + id: ConditionalAccessPolicy( + id=id, + display_name=display_name, + conditions=Conditions( + application_conditions=ApplicationsConditions( + included_applications=["All"], + excluded_applications=[], + included_user_actions=[], + ), + user_conditions=UsersConditions( + included_groups=[], + excluded_groups=[], + included_users=["All"], + excluded_users=[], + included_roles=[], + excluded_roles=[], + ), + client_app_types=[ + ClientAppType.EXCHANGE_ACTIVE_SYNC, + ClientAppType.OTHER_CLIENTS, + ], + user_risk_levels=[], + ), + grant_controls=GrantControls( + built_in_controls=[ + ConditionalAccessGrantControl.BLOCK, + ], + operator=GrantControlOperator.AND, + ), + session_controls=SessionControls( + persistent_browser=PersistentBrowser( + is_enabled=False, mode="always" + ), + sign_in_frequency=SignInFrequency( + is_enabled=False, + frequency=None, + type=None, + interval=SignInFrequencyInterval.EVERY_TIME, + ), + ), + state=ConditionalAccessPolicyState.ENABLED, + ) + } + + check = entra_legacy_authentication_blocked() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Conditional Access Policy '{display_name}' blocks legacy authentication." + ) + assert ( + result[0].resource + == entra_client.conditional_access_policies[id].dict() + ) + assert result[0].resource_name == display_name + assert result[0].resource_id == id + assert result[0].location == "global" From 51e796a48d4c24432c1215b255a1cdac6cdd740b Mon Sep 17 00:00:00 2001 From: Bogdan A Date: Mon, 31 Mar 2025 19:14:21 +0300 Subject: [PATCH 095/359] feat(gcp): add check for dormant (unused) SA keys (#7348) Co-authored-by: MrCloudSec Co-authored-by: Sergio Garcia --- README.md | 2 +- prowler/compliance/gcp/mitre_attack_gcp.json | 1 + .../__init__.py | 0 ...m_sa_user_managed_key_unused.metadata.json | 30 ++ .../iam_sa_user_managed_key_unused.py | 30 ++ .../services/monitoring/monitoring_service.py | 50 +++ tests/providers/gcp/gcp_fixtures.py | 39 +++ .../iam_sa_dormant_user_managed_keys_test.py | 286 ++++++++++++++++++ .../monitoring/monitoring_service_test.py | 22 ++ 9 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/__init__.py create mode 100644 prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json create mode 100644 prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py create mode 100644 tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py diff --git a/README.md b/README.md index c1b238fff5..3f51786d0f 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | |---|---|---|---|---| | AWS | 564 | 82 | 33 | 10 | -| GCP | 77 | 13 | 6 | 3 | +| GCP | 78 | 13 | 6 | 3 | | Azure | 140 | 18 | 7 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | | Microsoft365 | 5 | 2 | 1 | 0 | diff --git a/prowler/compliance/gcp/mitre_attack_gcp.json b/prowler/compliance/gcp/mitre_attack_gcp.json index 1c5af68300..6d57c7506b 100644 --- a/prowler/compliance/gcp/mitre_attack_gcp.json +++ b/prowler/compliance/gcp/mitre_attack_gcp.json @@ -141,6 +141,7 @@ "iam_organization_essential_contacts_configured", "iam_role_kms_enforce_separation_of_duties", "iam_role_sa_enforce_separation_of_duties", + "iam_sa_user_managed_key_unused", "iam_sa_no_administrative_privileges", "iam_sa_no_user_managed_keys", "iam_sa_user_managed_key_rotate_90_days", diff --git a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/__init__.py b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json new file mode 100644 index 0000000000..bc56488f9e --- /dev/null +++ b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "gcp", + "CheckID": "iam_sa_user_managed_key_unused", + "CheckTitle": "Ensure That There Are No Unused Service Account Keys for Each Service Account", + "CheckType": [], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "ServiceAccountKey", + "Description": "Ensure That There Are No Dormant Service Account Keys for Each Service Account. A key is considered dormant if it has been inactive for more than 180 days.", + "Risk": "Anyone who has access to the keys will be able to access resources through the service account. GCP-managed keys are used by Cloud Platform services such as App Engine and Compute Engine. These keys cannot be downloaded. Google will keep the keys and automatically rotate them on an approximately weekly basis. User-managed keys are created, downloadable, and managed by users.", + "RelatedUrl": "https://cloud.google.com/iam/docs/service-account-overview#identify-unused", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-user-managed-service-account-keys.html", + "Terraform": "" + }, + "Recommendation": { + "Text": "It is recommended to prevent user-managed service account keys.", + "Url": "https://cloud.google.com/iam/docs/creating-managing-service-account-keys" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py new file mode 100644 index 0000000000..73e45df6bf --- /dev/null +++ b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py @@ -0,0 +1,30 @@ +from prowler.lib.check.models import Check, Check_Report_GCP +from prowler.providers.gcp.services.iam.iam_client import iam_client +from prowler.providers.gcp.services.monitoring.monitoring_client import ( + monitoring_client, +) + + +class iam_sa_user_managed_key_unused(Check): + def execute(self) -> Check_Report_GCP: + findings = [] + keys_used = monitoring_client.sa_keys_metrics + for account in iam_client.service_accounts: + for key in account.keys: + if key.type == "USER_MANAGED": + report = Check_Report_GCP( + metadata=self.metadata(), + resource=account, + resource_id=key.name, + resource_name=account.email, + location=iam_client.region, + ) + if key.name in keys_used: + report.status = "PASS" + report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was used over the last 180 days." + else: + report.status = "FAIL" + report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was not used over the last 180 days." + findings.append(report) + + return findings diff --git a/prowler/providers/gcp/services/monitoring/monitoring_service.py b/prowler/providers/gcp/services/monitoring/monitoring_service.py index 89ae2d1ea2..426485c88f 100644 --- a/prowler/providers/gcp/services/monitoring/monitoring_service.py +++ b/prowler/providers/gcp/services/monitoring/monitoring_service.py @@ -1,3 +1,5 @@ +import datetime + from pydantic import BaseModel from prowler.lib.logger import logger @@ -9,7 +11,11 @@ class Monitoring(GCPService): def __init__(self, provider: GcpProvider): super().__init__(__class__.__name__, provider, api_version="v3") self.alert_policies = [] + self.sa_keys_metrics = set() self._get_alert_policies() + self._get_sa_keys_metrics( + "iam.googleapis.com/service_account/key/authn_events_count" + ) def _get_alert_policies(self): for project_id in self.project_ids: @@ -46,6 +52,50 @@ class Monitoring(GCPService): f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) + def _get_sa_keys_metrics(self, metric_type): + try: + end_time = ( + datetime.datetime.now(datetime.timezone.utc) + .replace(microsecond=0) + .isoformat() + ) + start_time = ( + ( + datetime.datetime.now(datetime.timezone.utc) + - datetime.timedelta(days=180) + ) + .replace(microsecond=0) + .isoformat() + ) + for project_id in self.project_ids: + try: + request = ( + self.client.projects() + .timeSeries() + .list( + name=f"projects/{project_id}", + filter=f'metric.type = "{metric_type}"', + interval_startTime=start_time, + interval_endTime=end_time, + view="HEADERS", + ) + ) + response = request.execute() + + for metric in response.get("timeSeries", []): + key_id = metric["metric"]["labels"].get("key_id") + if key_id: + self.sa_keys_metrics.add(key_id) + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + class AlertPolicy(BaseModel): name: str diff --git a/tests/providers/gcp/gcp_fixtures.py b/tests/providers/gcp/gcp_fixtures.py index d11b1cc508..31cb041455 100644 --- a/tests/providers/gcp/gcp_fixtures.py +++ b/tests/providers/gcp/gcp_fixtures.py @@ -351,6 +351,45 @@ def mock_api_projects_calls(client: MagicMock): }, ] } + + client.projects().timeSeries().list().execute.return_value = { + "timeSeries": [ + { + "metric": { + "labels": { + "key_id": "key1", + "type": "iam.googleapis.com/service_account/key/authn_events_count", + }, + "resource": { + "type": "iam_service_account", + "labels": { + "project_id": "{GCP_PROJECT_ID}", + "unique_id": "111222233334444", + }, + }, + "metricKind": "DELTA", + "valueType": "INT64", + } + }, + { + "metric": { + "labels": { + "key_id": "key2", + "type": "iam.googleapis.com/service_account/key/authn_events_count", + }, + "resource": { + "type": "iam_service_account", + "labels": { + "project_id": "{GCP_PROJECT_ID}", + "unique_id": "111222233334444", + }, + }, + "metricKind": "DELTA", + "valueType": "INT64", + } + }, + ] + } client.projects().alertPolicies().list_next.return_value = None # Used by IAM client.projects().serviceAccounts().list().execute.return_value = { diff --git a/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py b/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py new file mode 100644 index 0000000000..8cb9c7c832 --- /dev/null +++ b/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py @@ -0,0 +1,286 @@ +from datetime import datetime +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import ( + GCP_PROJECT_ID, + GCP_US_CENTER1_LOCATION, + set_mocked_gcp_provider, +) + + +class Test_iam_sa_user_managed_key_unused: + def test_iam_no_sa(self): + iam_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.iam_client", + new=iam_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused import ( + iam_sa_user_managed_key_unused, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + iam_client.service_accounts = [] + + check = iam_sa_user_managed_key_unused() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_dormant_no_keys(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused import ( + iam_sa_user_managed_key_unused, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + monitoring_client.sa_keys_metrics = set( + ["90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c"] + ) + + check = iam_sa_user_managed_key_unused() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_dormant_system_managed_keys(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused import ( + iam_sa_user_managed_key_unused, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="SYSTEM_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + monitoring_client.sa_keys_metrics = set( + ["90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c"] + ) + + check = iam_sa_user_managed_key_unused() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_user_managed_key_unused(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused import ( + iam_sa_user_managed_key_unused, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + monitoring_client.sa_keys_metrics = set( + ["90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c"] + ) + + check = iam_sa_user_managed_key_unused() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"User-managed key {iam_client.service_accounts[0].keys[0].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 180 days." + ) + assert result[0].resource_id == iam_client.service_accounts[0].keys[0].name + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].email + + def test_iam_sa_dormant_mixed_keys(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_unused.iam_sa_user_managed_key_unused import ( + iam_sa_user_managed_key_unused, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="SYSTEM_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ), + Key( + name="e5e3800831ac1adc8a5849da7d827b4724b1fce8", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ), + Key( + name="f8e4771561be5cda9b1267add7006c5143e3a220", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ), + ], + project_id=GCP_PROJECT_ID, + ) + ] + + monitoring_client.sa_keys_metrics = set( + ["f8e4771561be5cda9b1267add7006c5143e3a220"] + ) + + check = iam_sa_user_managed_key_unused() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"User-managed key {iam_client.service_accounts[0].keys[1].name} for Service Account {iam_client.service_accounts[0].email} was not used over the last 180 days." + ) + assert result[0].resource_id == iam_client.service_accounts[0].keys[1].name + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].email + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == f"User-managed key {iam_client.service_accounts[0].keys[2].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 180 days." + ) + assert result[1].resource_id == iam_client.service_accounts[0].keys[2].name + assert result[1].project_id == GCP_PROJECT_ID + assert result[1].location == GCP_US_CENTER1_LOCATION + assert result[1].resource_name == iam_client.service_accounts[0].email diff --git a/tests/providers/gcp/services/monitoring/monitoring_service_test.py b/tests/providers/gcp/services/monitoring/monitoring_service_test.py index 0db573a99d..2e3ec30637 100644 --- a/tests/providers/gcp/services/monitoring/monitoring_service_test.py +++ b/tests/providers/gcp/services/monitoring/monitoring_service_test.py @@ -41,3 +41,25 @@ class TestMonitoringService: assert monitoring_client.alert_policies[1].filters == [ 'metric.type="compute.googleapis.com/instance/disk/write_bytes_count"' ] + + def test_sa_keys_metrics(self): + with ( + patch( + "prowler.providers.gcp.lib.service.service.GCPService.__is_api_active__", + new=mock_is_api_active, + ), + patch( + "prowler.providers.gcp.lib.service.service.GCPService.__generate_client__", + new=mock_api_client, + ), + ): + monitoring_client = Monitoring( + set_mocked_gcp_provider(project_ids=[GCP_PROJECT_ID]) + ) + assert monitoring_client.service == "monitoring" + assert monitoring_client.project_ids == [GCP_PROJECT_ID] + + assert len(monitoring_client.sa_keys_metrics) == 2 + assert "key1" in monitoring_client.sa_keys_metrics + assert "key2" in monitoring_client.sa_keys_metrics + assert "key3" not in monitoring_client.sa_keys_metrics From dc953a6e225949793247655f6785906fa6ff8060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 31 Mar 2025 18:14:59 +0200 Subject: [PATCH 096/359] docs(python): add annotations about Python version (#7402) --- docs/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/index.md b/docs/index.md index 628f9bf7ce..52c37e29cf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -136,7 +136,7 @@ Prowler App can be installed in different ways, depending on your environment: ### Prowler CLI Installation -Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), thus can be installed as Python package with `Python >= 3.9`: +Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), thus can be installed as Python package with `Python >= 3.9, <= 3.12`: === "pipx" @@ -144,7 +144,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), _Requirements_: - * `Python >= 3.9` + * `Python >= 3.9, <= 3.12` * `pipx` installed: [pipx installation](https://pipx.pypa.io/stable/installation/). * AWS, GCP, Azure and/or Kubernetes credentials @@ -168,7 +168,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), _Requirements_: - * `Python >= 3.9` + * `Python >= 3.9, <= 3.12` * `Python pip >= 21.0.0` * AWS, GCP, Azure, Microsoft365 and/or Kubernetes credentials @@ -228,7 +228,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), _Requirements_: - * `Python >= 3.9` + * `Python >= 3.9, <= 3.12` * AWS, GCP, Azure and/or Kubernetes credentials _Commands_: @@ -244,8 +244,8 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), _Requirements_: - * `Ubuntu 23.04` or above, if you are using an older version of Ubuntu check [pipx installation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#__tabbed_1_1) and ensure you have `Python >= 3.9`. - * `Python >= 3.9` + * `Ubuntu 23.04` or above, if you are using an older version of Ubuntu check [pipx installation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#__tabbed_1_1) and ensure you have `Python >= 3.9, <= 3.12`. + * `Python >= 3.9, <= 3.12` * AWS, GCP, Azure and/or Kubernetes credentials _Commands_: From 97db38aa25132513a9235fe9f9dcf6325a7dfb7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:29:31 +0200 Subject: [PATCH 097/359] chore(deps): bump azure-mgmt-containerregistry from 10.3.0 to 12.0.0 (#7025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 17 +++++++++-------- pyproject.toml | 2 +- ...containerregistry_uses_private_link_test.py | 18 +++--------------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5c46be35d2..50a8999646 100644 --- a/poetry.lock +++ b/poetry.lock @@ -424,20 +424,21 @@ typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-containerregistry" -version = "10.3.0" +version = "12.0.0" description = "Microsoft Azure Container Registry Client Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-containerregistry-10.3.0.tar.gz", hash = "sha256:ae21651855dfb19c42d91d6b3a965c6c611e23f8bc4bf7138835e652d2f918e3"}, - {file = "azure_mgmt_containerregistry-10.3.0-py3-none-any.whl", hash = "sha256:851e1c57f9bc4a3589c6b21fb627c11fd6cbb57a0388b7dfccd530ba3160805f"}, + {file = "azure_mgmt_containerregistry-12.0.0-py3-none-any.whl", hash = "sha256:464abd4d3d9ecc0456ed8f63a6b9b93afc2e3e194f2d34f26a758afb67ad3b5c"}, + {file = "azure_mgmt_containerregistry-12.0.0.tar.gz", hash = "sha256:f19f8faa7881deaf2b5015c0eb050a92e2380cd9d18dee33cdb5f27d44a06c03"}, ] [package.dependencies] -azure-common = ">=1.1,<2.0" -azure-mgmt-core = ">=1.3.2,<2.0.0" -isodate = ">=0.6.1,<1.0.0" +azure-common = ">=1.1" +azure-mgmt-core = ">=1.3.2" +isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-containerservice" @@ -5336,4 +5337,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "04a5713e73ad4eee7eb3e9f1c72504f2488374f4b134600f87c8c31aab9f8684" +content-hash = "40634eb731e69a9732fdd67e108def20e8d1f33c77acd6ea414cf35034fcacc4" diff --git a/pyproject.toml b/pyproject.toml index 1d263b0793..52fb609fa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [ "azure-mgmt-applicationinsights==4.0.0", "azure-mgmt-authorization==4.0.0", "azure-mgmt-compute==34.0.0", - "azure-mgmt-containerregistry==10.3.0", + "azure-mgmt-containerregistry==12.0.0", "azure-mgmt-containerservice==34.1.0", "azure-mgmt-cosmosdb==9.7.0", "azure-mgmt-keyvault==10.3.1", diff --git a/tests/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link_test.py b/tests/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link_test.py index c49da40f98..f8b9237a21 100644 --- a/tests/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link_test.py +++ b/tests/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link_test.py @@ -2,12 +2,6 @@ from unittest import mock from unittest.mock import MagicMock from uuid import uuid4 -from azure.mgmt.containerregistry.models import ( - PrivateEndpoint, - PrivateEndpointConnection, - PrivateLinkServiceConnectionState, -) - from tests.providers.azure.azure_fixtures import ( AZURE_SUBSCRIPTION_ID, set_mocked_azure_provider, @@ -110,6 +104,7 @@ class Test_containerregistry_uses_private_link: ): from prowler.providers.azure.services.containerregistry.containerregistry_service import ( ContainerRegistryInfo, + PrivateEndpointConnection, ) from prowler.providers.azure.services.containerregistry.containerregistry_uses_private_link.containerregistry_uses_private_link import ( containerregistry_uses_private_link, @@ -132,15 +127,8 @@ class Test_containerregistry_uses_private_link: private_endpoint_connections=[ PrivateEndpointConnection( id="/subscriptions/AZURE_SUBSCRIPTION_ID/resourceGroups/mock_resource_group/providers/Microsoft.ContainerRegistry/registries/mock_registry/privateEndpointConnections/myConnection", - private_endpoint=PrivateEndpoint( - id="/subscriptions/AZURE_SUBSCRIPTION_ID/resourceGroups/mock_resource_group/providers/Microsoft.Network/privateEndpoints/myPrivateEndpoint" - ), - private_link_service_connection_state=PrivateLinkServiceConnectionState( - status="Approved", - description="Auto-approved connection", - actions_required="None", - ), - provisioning_state="Succeeded", + name="myConnection", + type="Microsoft.ContainerRegistry/registries/privateEndpointConnections", ) ], ) From 228dd2952a9c3a0a2652a2c100ca023268628272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Tue, 1 Apr 2025 11:55:14 +0200 Subject: [PATCH 098/359] fix(scans): Handle duplicated scan tasks (#7401) --- api/CHANGELOG.md | 7 ++++++ api/src/backend/tasks/tasks.py | 45 +++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 09cc4369ae..db0d696488 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -15,6 +15,13 @@ All notable changes to the **Prowler API** are documented in this file. --- +## [v1.5.3] (Prowler v5.4.3) + +### Fixed +- Added duplicated scheduled scans handling ([#7401])(https://github.com/prowler-cloud/prowler/pull/7401). + +--- + ## [v1.5.2] (Prowler v5.4.2) ### Changed diff --git a/api/src/backend/tasks/tasks.py b/api/src/backend/tasks/tasks.py index c9b8d1ab2a..12e7c7cf01 100644 --- a/api/src/backend/tasks/tasks.py +++ b/api/src/backend/tasks/tasks.py @@ -1,3 +1,4 @@ +from datetime import datetime, timedelta, timezone from pathlib import Path from shutil import rmtree @@ -21,6 +22,7 @@ from api.db_utils import rls_transaction from api.decorators import set_tenant from api.models import Finding, Provider, Scan, ScanSummary, StateChoices from api.utils import initialize_prowler_provider +from api.v1.serializers import ScanTaskSerializer from prowler.lib.outputs.finding import Finding as FindingOutput logger = get_task_logger(__name__) @@ -128,6 +130,43 @@ def perform_scheduled_scan_task(self, tenant_id: str, provider_id: str): periodic_task_instance = PeriodicTask.objects.get( name=f"scan-perform-scheduled-{provider_id}" ) + + executed_scan = Scan.objects.filter( + tenant_id=tenant_id, + provider_id=provider_id, + task__task_runner_task__task_id=task_id, + ).order_by("completed_at") + + if ( + Scan.objects.filter( + tenant_id=tenant_id, + provider_id=provider_id, + trigger=Scan.TriggerChoices.SCHEDULED, + state=StateChoices.EXECUTING, + scheduler_task_id=periodic_task_instance.id, + scheduled_at__date=datetime.now(timezone.utc).date(), + ).exists() + or executed_scan.exists() + ): + # Duplicated task execution due to visibility timeout or scan is already running + logger.warning(f"Duplicated scheduled scan for provider {provider_id}.") + try: + affected_scan = executed_scan.first() + if not affected_scan: + raise ValueError( + "Error retrieving affected scan details after detecting duplicated scheduled " + "scan." + ) + # Return the affected scan details to avoid losing data + serializer = ScanTaskSerializer(instance=affected_scan) + except Exception as duplicated_scan_exception: + logger.error( + f"Duplicated scheduled scan for provider {provider_id}. Error retrieving affected scan details: " + f"{str(duplicated_scan_exception)}" + ) + raise duplicated_scan_exception + return serializer.data + next_scan_datetime = get_next_execution_datetime(task_id, provider_id) scan_instance, _ = Scan.objects.get_or_create( tenant_id=tenant_id, @@ -135,7 +174,11 @@ def perform_scheduled_scan_task(self, tenant_id: str, provider_id: str): trigger=Scan.TriggerChoices.SCHEDULED, state__in=(StateChoices.SCHEDULED, StateChoices.AVAILABLE), scheduler_task_id=periodic_task_instance.id, - defaults={"state": StateChoices.SCHEDULED}, + defaults={ + "state": StateChoices.SCHEDULED, + "name": "Daily scheduled scan", + "scheduled_at": next_scan_datetime - timedelta(days=1), + }, ) scan_instance.task_id = task_id From 191fbf01779f26f20a9aab235988a6f030ef7cea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:55:37 +0200 Subject: [PATCH 099/359] chore(deps): bump azure-mgmt-applicationinsights from 4.0.0 to 4.1.0 (#7161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 17 +++++++++-------- pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index 50a8999646..6c268d0b99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -372,20 +372,21 @@ typing-extensions = ">=4.0.1" [[package]] name = "azure-mgmt-applicationinsights" -version = "4.0.0" +version = "4.1.0" description = "Microsoft Azure Application Insights Management Client Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-applicationinsights-4.0.0.zip", hash = "sha256:50c3db05573e0cc2d56314a0556fb346ef05ec489ac000f4d720d92c6b647e06"}, - {file = "azure_mgmt_applicationinsights-4.0.0-py3-none-any.whl", hash = "sha256:2b1ffd9a0114974455795c73a3a5d17c849e32b961d707d2db393b99254b576f"}, + {file = "azure_mgmt_applicationinsights-4.1.0-py3-none-any.whl", hash = "sha256:9e71f29b01e505a773501451d12fd6a10482cf4b13e9ac2bff72f5380496d979"}, + {file = "azure_mgmt_applicationinsights-4.1.0.tar.gz", hash = "sha256:15531390f12ce3d767cd3f1949af36aa39077c145c952fec4d80303c86ec7b6c"}, ] [package.dependencies] -azure-common = ">=1.1,<2.0" -azure-mgmt-core = ">=1.3.2,<2.0.0" -isodate = ">=0.6.1,<1.0.0" +azure-common = ">=1.1" +azure-mgmt-core = ">=1.3.2" +isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-authorization" @@ -5337,4 +5338,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "40634eb731e69a9732fdd67e108def20e8d1f33c77acd6ea414cf35034fcacc4" +content-hash = "d711bb44227117b377d4b211a072d596a74ae8a53f883f8c786c1743d5241db6" diff --git a/pyproject.toml b/pyproject.toml index 52fb609fa9..864a88509e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [ "alive-progress==3.2.0", "azure-identity==1.19.0", "azure-keyvault-keys==4.10.0", - "azure-mgmt-applicationinsights==4.0.0", + "azure-mgmt-applicationinsights==4.1.0", "azure-mgmt-authorization==4.0.0", "azure-mgmt-compute==34.0.0", "azure-mgmt-containerregistry==12.0.0", From 6a3b8c4674b57c18852730dcdb2ac2817ff2439a Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 1 Apr 2025 19:14:15 +0200 Subject: [PATCH 100/359] feat(entra): add new check `entra_admin_users_cloud_only` (#7286) --- .../entra_admin_users_cloud_only/__init__.py | 0 ...entra_admin_users_cloud_only.metadata.json | 30 ++ .../entra_admin_users_cloud_only.py | 49 +++ .../services/entra/entra_service.py | 48 +++ .../entra_admin_users_cloud_only_test.py | 311 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 51 +++ 6 files changed, 489 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/__init__.py create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json create mode 100644 prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py create mode 100644 tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/__init__.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json b/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json new file mode 100644 index 0000000000..e507677a0d --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "microsoft365", + "CheckID": "entra_admin_users_cloud_only", + "CheckTitle": "Ensure all Microsoft 365 administrative users are cloud-only", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Administrative User", + "Description": "This check verifies that all Microsoft 365 administrative users are cloud-only, not synchronized from an on-premises directory, by querying administrative users and checking their synchronization status.", + "Risk": "On-premises synchronized administrative users increase the attack surface and compromise the security posture of the cloud environment. Compromise of on-premises systems could lead to unauthorized access to Microsoft 365 administrative functionalities.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/best-practices#9-use-cloud-native-accounts-for-microsoft-entra-roles", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Identify on-premises synchronized administrative users using Microsoft Entra Connect or equivalent tools.\n2. Create new cloud-only administrative user with appropriate permissions.\n3. Migrate administrative tasks from on-premises synchronized users to the new cloud-only user.\n4. Disable or remove the on-premises synchronized administrative users.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure all Microsoft 365 administrative users are cloud-only to reduce the attack surface and improve security posture.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/best-practices#9-use-cloud-native-accounts-for-microsoft-entra-roles" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py b/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py new file mode 100644 index 0000000000..7ea617ca0e --- /dev/null +++ b/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py @@ -0,0 +1,49 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportMicrosoft365 +from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.providers.microsoft365.services.entra.entra_service import AdminRoles + + +class entra_admin_users_cloud_only(Check): + """ + Check to ensure that there are no admin accounts with non-cloud-only accounts in Microsoft 365. + This check verifies if any user with admin roles has an on-premises synchronized account. + If such users are found, the check will fail. + """ + + def execute(self) -> List[CheckReportMicrosoft365]: + """ + Execute the check to identify admin accounts with non-cloud-only accounts. + Returns: + List[CheckReportMicrosoft365]: A list containing the check report with the status and details. + """ + findings = [] + if entra_client.users: + non_cloud_admins = [] + for user_id, user in entra_client.users.items(): + for role in user.directory_roles_ids: + if ( + role in {admin_role.value for admin_role in AdminRoles} + and user.on_premises_sync_enabled + ): + non_cloud_admins.append(user_id) + + report = CheckReportMicrosoft365( + metadata=self.metadata(), + resource={}, + resource_name="Cloud-only account", + resource_id="cloudOnlyAccount", + ) + report.status = "PASS" + report.status_extended = ( + "All the users with administrative roles are cloud-only accounts." + ) + + if non_cloud_admins: + report.status = "FAIL" + ids_str = ", ".join(non_cloud_admins) + report.status_extended = f"There are some users with administrative roles that are not cloud-only accounts: {ids_str}" + + findings.append(report) + return findings diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py index 557077f3bc..16594a8941 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -1,3 +1,4 @@ +import asyncio from asyncio import gather, get_event_loop from enum import Enum from typing import List, Optional @@ -23,6 +24,7 @@ class Entra(Microsoft365Service): self._get_admin_consent_policy(), self._get_groups(), self._get_organization(), + self._get_users(), ) ) @@ -31,6 +33,7 @@ class Entra(Microsoft365Service): self.admin_consent_policy = attributes[2] self.groups = attributes[3] self.organizations = attributes[4] + self.users = attributes[5] async def _get_authorization_policy(self): logger.info("Entra - Getting authorization policy...") @@ -351,6 +354,44 @@ class Entra(Microsoft365Service): return organizations + async def _get_users(self): + logger.info("Entra - Getting users...") + users = {} + try: + users_list = await self.client.users.get() + directory_roles = await self.client.directory_roles.get() + + async def fetch_role_members(directory_role): + members_response = ( + await self.client.directory_roles.by_directory_role_id( + directory_role.id + ).members.get() + ) + return directory_role.role_template_id, members_response.value + + tasks = [fetch_role_members(role) for role in directory_roles.value] + roles_members_list = await asyncio.gather(*tasks) + + user_roles_map = {} + for role_template_id, members in roles_members_list: + for member in members: + user_roles_map.setdefault(member.id, []).append(role_template_id) + + for user in users_list.value: + users[user.id] = User( + id=user.id, + name=user.display_name, + on_premises_sync_enabled=( + True if (user.on_premises_sync_enabled) else False + ), + directory_roles_ids=user_roles_map.get(user.id, []), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return users + class ConditionalAccessPolicyState(Enum): ENABLED = "enabled" @@ -517,6 +558,13 @@ class AdminRoles(Enum): USER_ADMINISTRATOR = "fe930be7-5e62-47db-91af-98c3a49a38b1" +class User(BaseModel): + id: str + name: str + on_premises_sync_enabled: bool + directory_roles_ids: List[str] = [] + + class InvitationsFrom(Enum): NONE = "none" ADMINS_AND_GUEST_INVITERS = "adminsAndGuestInviters" diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py b/tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py new file mode 100644 index 0000000000..4e718d29f7 --- /dev/null +++ b/tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py @@ -0,0 +1,311 @@ +from unittest import mock + +from prowler.providers.microsoft365.services.entra.entra_service import AdminRoles, User +from tests.providers.microsoft365.microsoft365_fixtures import ( + set_mocked_microsoft365_provider, +) + + +class Test_entra_admin_users_cloud_only: + def test_admin_accounts_are_cloud_only(self): + """ + Test when all admin accounts are cloud-only: + The check should PASS because there are no non-cloud-only admin accounts. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + entra_client.users = { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + } + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "All the users with administrative roles are cloud-only accounts." + ) + assert result[0].resource_id == "cloudOnlyAccount" + assert result[0].location == "global" + assert result[0].resource_name == "Cloud-only account" + assert result[0].resource == {} + + def test_some_admin_accounts_are_not_cloud(self): + """ + Test when some admin accounts are not cloud-only: + The check should FAIL because there are non-cloud-only admin accounts. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + entra_client.users = { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + } + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "There are some users with administrative roles that are not cloud-only accounts: user-2" + ) + assert result[0].resource_id == "cloudOnlyAccount" + assert result[0].location == "global" + assert result[0].resource_name == "Cloud-only account" + assert result[0].resource == {} + + def test_all_admin_account_are_not_cloud(self): + """ + Test when all admin accounts are not cloud-only: + The check should FAIL because all admin accounts are non-cloud-only. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + entra_client.users = { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + } + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "There are some users with administrative roles that are not cloud-only accounts: user-1, user-2, user-3" + ) + assert result[0].resource_id == "cloudOnlyAccount" + assert result[0].location == "global" + assert result[0].resource_name == "Cloud-only account" + assert result[0].resource == {} + + def test_only_user_accounts_are_not_cloud(self): + """ + Test when only user accounts are not cloud-only: + The check should PASS because there are no non-cloud-only admin accounts. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + entra_client.users = { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=["user-id-role"], + on_premises_sync_enabled=True, + ), + } + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "All the users with administrative roles are cloud-only accounts." + ) + assert result[0].resource_id == "cloudOnlyAccount" + assert result[0].location == "global" + assert result[0].resource_name == "Cloud-only account" + assert result[0].resource == {} + + def test_no_admin_accounts(self): + """ + Test when there are no admin accounts: + The check should PASS because there are no non-cloud-only admin accounts. + """ + entra_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + entra_client.users = { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=["user-id-role"], + on_premises_sync_enabled=True, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=["user-id-role"], + on_premises_sync_enabled=False, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=["user-id-role"], + on_premises_sync_enabled=False, + ), + } + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "All the users with administrative roles are cloud-only accounts." + ) + assert result[0].resource_id == "cloudOnlyAccount" + assert result[0].location == "global" + assert result[0].resource_name == "Cloud-only account" + assert result[0].resource == {} + + def test_no_users(self): + """ + Test when there are no users: + The check should return an empty list of findings. + """ + entra_client = mock.MagicMock() + entra_client.users = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_microsoft365_provider(), + ), + mock.patch( + "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + new=entra_client, + ), + ): + from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + entra_admin_users_cloud_only, + ) + + check = entra_admin_users_cloud_only() + result = check.execute() + + assert len(result) == 0 + assert result == [] diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py index 19a027e60c..8c9e8128c1 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py @@ -3,6 +3,7 @@ from unittest.mock import patch from prowler.providers.microsoft365.models import Microsoft365IdentityInfo from prowler.providers.microsoft365.services.entra.entra_service import ( AdminConsentPolicy, + AdminRoles, ApplicationsConditions, AuthenticationStrength, AuthorizationPolicy, @@ -22,6 +23,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequency, SignInFrequencyInterval, SignInFrequencyType, + User, UserAction, UsersConditions, ) @@ -115,6 +117,29 @@ async def mock_entra_get_admin_consent_policy(_): ) +async def mock_entra_get_users(_): + return { + "user-1": User( + id="user-1", + name="User 1", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + "user-2": User( + id="user-2", + name="User 2", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=False, + ), + "user-3": User( + id="user-3", + name="User 3", + directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], + on_premises_sync_enabled=True, + ), + } + + async def mock_entra_get_organization(_): return [ Organization( @@ -245,3 +270,29 @@ class Test_Entra_Service: assert entra_client.organizations[0].id == "org1" assert entra_client.organizations[0].name == "Organization 1" assert entra_client.organizations[0].on_premises_sync_enabled + + @patch( + "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_users", + new=mock_entra_get_users, + ) + def test_get_users(self): + entra_client = Entra(set_mocked_microsoft365_provider()) + assert len(entra_client.users) == 3 + assert entra_client.users["user-1"].id == "user-1" + assert entra_client.users["user-1"].name == "User 1" + assert entra_client.users["user-1"].directory_roles_ids == [ + AdminRoles.GLOBAL_ADMINISTRATOR.value + ] + assert entra_client.users["user-1"].on_premises_sync_enabled + assert entra_client.users["user-2"].id == "user-2" + assert entra_client.users["user-2"].name == "User 2" + assert entra_client.users["user-2"].directory_roles_ids == [ + AdminRoles.GLOBAL_ADMINISTRATOR.value + ] + assert not entra_client.users["user-2"].on_premises_sync_enabled + assert entra_client.users["user-3"].id == "user-3" + assert entra_client.users["user-3"].name == "User 3" + assert entra_client.users["user-3"].directory_roles_ids == [ + AdminRoles.GLOBAL_ADMINISTRATOR.value + ] + assert entra_client.users["user-3"].on_premises_sync_enabled From 2719991630d3ecd4f49d7aea4efb57dc176913ed Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 1 Apr 2025 20:24:18 +0200 Subject: [PATCH 101/359] fix(report): log as error when Resource ID or Name do not exist (#7411) --- prowler/lib/outputs/finding.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index f41ed6d935..717783b75b 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -258,12 +258,21 @@ class Finding(BaseModel): # check_output Unique ID # TODO: move this to a function - # TODO: in Azure, GCP and K8s there are fidings without resource_name + # TODO: in Azure, GCP and K8s there are findings without resource_name output_data["uid"] = ( f"prowler-{provider.type}-{check_output.check_metadata.CheckID}-{output_data['account_uid']}-" f"{output_data['region']}-{output_data['resource_name']}" ) + if not output_data["resource_uid"]: + logger.error( + f"Check {check_output.check_metadata.CheckID} has no resource_id." + ) + if not output_data["resource_name"]: + logger.error( + f"Check {check_output.check_metadata.CheckID} has no resource_name." + ) + return cls(**output_data) except ValidationError as validation_error: logger.error( From 5a59bb335c541ec0e5e4b6955c0692801a4982d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Tue, 1 Apr 2025 20:30:37 +0200 Subject: [PATCH 102/359] fix(resources): add the correct id and names for resources (#7410) --- .../defender_container_images_scan_enabled.py | 1 - ..._ensure_defender_for_azure_sql_databases_is_on.py | 1 - .../defender_ensure_defender_for_containers_is_on.py | 1 - .../azure/services/defender/defender_service.py | 2 ++ .../compute_project_os_login_enabled.py | 1 + .../iam_audit_logs_enabled/iam_audit_logs_enabled.py | 1 + .../defender_container_images_scan_enabled_test.py | 10 +++++++--- ...er_ensure_defender_for_app_services_is_on_test.py | 2 ++ .../defender_ensure_defender_for_arm_is_on_test.py | 2 ++ ...re_defender_for_azure_sql_databases_is_on_test.py | 6 ++++-- ...nder_ensure_defender_for_containers_is_on_test.py | 6 ++++-- ...fender_ensure_defender_for_cosmosdb_is_on_test.py | 2 ++ ...ender_ensure_defender_for_databases_is_on_test.py | 12 ++++++++++++ .../defender_ensure_defender_for_dns_is_on_test.py | 2 ++ ...fender_ensure_defender_for_keyvault_is_on_test.py | 2 ++ ...efender_for_os_relational_databases_is_on_test.py | 2 ++ ...defender_ensure_defender_for_server_is_on_test.py | 2 ++ ...der_ensure_defender_for_sql_servers_is_on_test.py | 2 ++ ...efender_ensure_defender_for_storage_is_on_test.py | 2 ++ .../azure/services/defender/defender_service_test.py | 5 +++++ .../compute_project_os_login_enabled_test.py | 2 ++ .../iam_audit_logs_enabled_test.py | 2 ++ 22 files changed, 58 insertions(+), 10 deletions(-) diff --git a/prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.py b/prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.py index 9aa966e608..06b067d1a4 100644 --- a/prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.py +++ b/prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.py @@ -11,7 +11,6 @@ class defender_container_images_scan_enabled(Check): metadata=self.metadata(), resource=pricings["Containers"] ) report.subscription = subscription - report.resource_name = "Dender plan for Containers" report.status = "PASS" report.status_extended = ( f"Container image scan is enabled in subscription {subscription}." diff --git a/prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.py b/prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.py index 5dc3220cf1..3b05ddd415 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.py +++ b/prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.py @@ -11,7 +11,6 @@ class defender_ensure_defender_for_azure_sql_databases_is_on(Check): metadata=self.metadata(), resource=pricings["SqlServers"] ) report.subscription = subscription - report.resource_name = "Defender plan Azure SQL DB Servers" report.status = "PASS" report.status_extended = f"Defender plan Defender for Azure SQL DB Servers from subscription {subscription} is set to ON (pricing tier standard)." if pricings["SqlServers"].pricing_tier != "Standard": diff --git a/prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.py b/prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.py index 3771b0ecfd..56a5ff32e3 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.py +++ b/prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.py @@ -11,7 +11,6 @@ class defender_ensure_defender_for_containers_is_on(Check): metadata=self.metadata(), resource=pricings["Containers"] ) report.subscription = subscription - report.resource_name = "Defender plan Container Registries" report.status = "PASS" report.status_extended = f"Defender plan Defender for Containers from subscription {subscription} is set to ON (pricing tier standard)." if pricings["Containers"].pricing_tier != "Standard": diff --git a/prowler/providers/azure/services/defender/defender_service.py b/prowler/providers/azure/services/defender/defender_service.py index ef90ed7e70..3253ebba60 100644 --- a/prowler/providers/azure/services/defender/defender_service.py +++ b/prowler/providers/azure/services/defender/defender_service.py @@ -39,6 +39,7 @@ class Defender(AzureService): { pricing.name: Pricing( resource_id=pricing.id, + resource_name=pricing.name, pricing_tier=getattr(pricing, "pricing_tier", None), free_trial_remaining_time=pricing.free_trial_remaining_time, extensions=dict( @@ -224,6 +225,7 @@ class Defender(AzureService): class Pricing(BaseModel): resource_id: str + resource_name: str pricing_tier: str free_trial_remaining_time: timedelta extensions: Dict[str, bool] = {} diff --git a/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py b/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py index 436fef35d8..4d168ad7b8 100644 --- a/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py +++ b/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py @@ -9,6 +9,7 @@ class compute_project_os_login_enabled(Check): report = Check_Report_GCP( metadata=self.metadata(), resource=project, + resource_name=project.id, project_id=project.id, location=compute_client.region, ) diff --git a/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py b/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py index e6451181ec..a07758aa20 100644 --- a/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py +++ b/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py @@ -11,6 +11,7 @@ class iam_audit_logs_enabled(Check): report = Check_Report_GCP( metadata=self.metadata(), resource=project, + resource_name=project.id, project_id=project.id, location=cloudresourcemanager_client.region, ) diff --git a/tests/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled_test.py b/tests/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled_test.py index 13bbd57838..6bb9fb0e9a 100644 --- a/tests/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled_test.py +++ b/tests/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled_test.py @@ -60,6 +60,7 @@ class Test_defender_container_images_scan_enabled: AZURE_SUBSCRIPTION_ID: { "NotContainers": Pricing( resource_id=str(uuid4()), + resource_name="Defender plan Servers", pricing_tier="Free", free_trial_remaining_time=timedelta(days=1), ) @@ -90,6 +91,7 @@ class Test_defender_container_images_scan_enabled: AZURE_SUBSCRIPTION_ID: { "Containers": Pricing( resource_id=str(uuid4()), + resource_name="Defender plan for Containers", pricing_tier="Free", free_trial_remaining_time=timedelta(days=1), extensions={}, @@ -124,7 +126,7 @@ class Test_defender_container_images_scan_enabled: "Containers" ].resource_id ) - assert result[0].resource_name == "Dender plan for Containers" + assert result[0].resource_name == "Defender plan for Containers" assert result[0].subscription == AZURE_SUBSCRIPTION_ID def test_defender_subscription_containers_container_images_scan_off(self): @@ -133,6 +135,7 @@ class Test_defender_container_images_scan_enabled: AZURE_SUBSCRIPTION_ID: { "Containers": Pricing( resource_id=str(uuid4()), + resource_name="Defender plan for Containers", pricing_tier="Free", free_trial_remaining_time=timedelta(days=1), extensions={"ContainerRegistriesVulnerabilityAssessments": False}, @@ -167,7 +170,7 @@ class Test_defender_container_images_scan_enabled: "Containers" ].resource_id ) - assert result[0].resource_name == "Dender plan for Containers" + assert result[0].resource_name == "Defender plan for Containers" assert result[0].subscription == AZURE_SUBSCRIPTION_ID def test_defender_subscription_containers_container_images_scan_on(self): @@ -176,6 +179,7 @@ class Test_defender_container_images_scan_enabled: AZURE_SUBSCRIPTION_ID: { "Containers": Pricing( resource_id=str(uuid4()), + resource_name="Defender plan for Containers", pricing_tier="Free", free_trial_remaining_time=timedelta(days=1), extensions={"ContainerRegistriesVulnerabilityAssessments": True}, @@ -210,5 +214,5 @@ class Test_defender_container_images_scan_enabled: "Containers" ].resource_id ) - assert result[0].resource_name == "Dender plan for Containers" + assert result[0].resource_name == "Defender plan for Containers" assert result[0].subscription == AZURE_SUBSCRIPTION_ID diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on_test.py index e3c83045f7..a3b10bb0d4 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_app_services_is_on: AZURE_SUBSCRIPTION_ID: { "AppServices": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_app_services_is_on: AZURE_SUBSCRIPTION_ID: { "AppServices": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on_test.py index 4341ce9e08..247cebf877 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_arm_is_on: AZURE_SUBSCRIPTION_ID: { "Arm": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_arm_is_on: AZURE_SUBSCRIPTION_ID: { "Arm": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on_test.py index 15269e71f1..5a0ab49b7a 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_azure_sql_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -67,7 +68,7 @@ class Test_defender_ensure_defender_for_azure_sql_databases_is_on: == f"Defender plan Defender for Azure SQL DB Servers from subscription {AZURE_SUBSCRIPTION_ID} is set to OFF (pricing tier not standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Azure SQL DB Servers" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id def test_defender_sql_databases_pricing_tier_standard(self): @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_azure_sql_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -106,5 +108,5 @@ class Test_defender_ensure_defender_for_azure_sql_databases_is_on: == f"Defender plan Defender for Azure SQL DB Servers from subscription {AZURE_SUBSCRIPTION_ID} is set to ON (pricing tier standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Azure SQL DB Servers" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on_test.py index d40fbe1b1c..622ad77b42 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_containers_is_on: AZURE_SUBSCRIPTION_ID: { "Containers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -67,7 +68,7 @@ class Test_defender_ensure_defender_for_containers_is_on: == f"Defender plan Defender for Containers from subscription {AZURE_SUBSCRIPTION_ID} is set to OFF (pricing tier not standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Container Registries" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id def test_defender_container_registries_pricing_tier_standard(self): @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_containers_is_on: AZURE_SUBSCRIPTION_ID: { "Containers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -106,5 +108,5 @@ class Test_defender_ensure_defender_for_containers_is_on: == f"Defender plan Defender for Containers from subscription {AZURE_SUBSCRIPTION_ID} is set to ON (pricing tier standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Container Registries" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on_test.py index 5f7906e1c2..21507b9c20 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_cosmosdb_is_on: AZURE_SUBSCRIPTION_ID: { "CosmosDbs": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_cosmosdb_is_on: AZURE_SUBSCRIPTION_ID: { "CosmosDbs": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py index 755151da20..c4b6d641d4 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -69,6 +70,7 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServerVirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -100,6 +102,7 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "OpenSourceRelationalDatabases": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -131,6 +134,7 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "CosmosDbs": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) @@ -162,21 +166,25 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "SqlServerVirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "OpenSourceRelationalDatabases": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "CosmosDbs": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), @@ -216,21 +224,25 @@ class Test_defender_ensure_defender_for_databases_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServers": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "SqlServerVirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "OpenSourceRelationalDatabases": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ), "CosmosDbs": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ), diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on_test.py index 64d81487f0..22729f4677 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_dns_is_on: AZURE_SUBSCRIPTION_ID: { "Dns": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_dns_is_on: AZURE_SUBSCRIPTION_ID: { "Dns": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on_test.py index 4c4315e75c..f2ef503114 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_keyvault_is_on: AZURE_SUBSCRIPTION_ID: { "KeyVaults": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_keyvault_is_on: AZURE_SUBSCRIPTION_ID: { "KeyVaults": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on_test.py index 48ddb8b72d..a00ad47526 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_os_relational_databases_is_on: AZURE_SUBSCRIPTION_ID: { "OpenSourceRelationalDatabases": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -80,6 +81,7 @@ class Test_defender_ensure_defender_for_os_relational_databases_is_on: AZURE_SUBSCRIPTION_ID: { "OpenSourceRelationalDatabases": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on_test.py index 17405d9f6d..460a206150 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_server_is_on: AZURE_SUBSCRIPTION_ID: { "VirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_server_is_on: AZURE_SUBSCRIPTION_ID: { "VirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on_test.py index 72e1f82257..c99a270e89 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_sql_servers_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServerVirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_sql_servers_is_on: AZURE_SUBSCRIPTION_ID: { "SqlServerVirtualMachines": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on_test.py index 53db01231c..d3d22ee1d7 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_defender_for_storage_is_on: AZURE_SUBSCRIPTION_ID: { "StorageAccounts": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Not Standard", free_trial_remaining_time=0, ) @@ -77,6 +78,7 @@ class Test_defender_ensure_defender_for_storage_is_on: AZURE_SUBSCRIPTION_ID: { "StorageAccounts": Pricing( resource_id=resource_id, + resource_name="Defender plan Servers", pricing_tier="Standard", free_trial_remaining_time=0, ) diff --git a/tests/providers/azure/services/defender/defender_service_test.py b/tests/providers/azure/services/defender/defender_service_test.py index 8fb0437338..ccf4260885 100644 --- a/tests/providers/azure/services/defender/defender_service_test.py +++ b/tests/providers/azure/services/defender/defender_service_test.py @@ -21,6 +21,7 @@ def mock_defender_get_pricings(_): AZURE_SUBSCRIPTION_ID: { "Standard": Pricing( resource_id="resource_id", + resource_name="resource_name", pricing_tier="pricing_tier", free_trial_remaining_time=timedelta(days=1), extensions={}, @@ -140,6 +141,10 @@ class Test_Defender_Service: defender.pricings[AZURE_SUBSCRIPTION_ID]["Standard"].resource_id == "resource_id" ) + assert ( + defender.pricings[AZURE_SUBSCRIPTION_ID]["Standard"].resource_name + == "resource_name" + ) assert ( defender.pricings[AZURE_SUBSCRIPTION_ID]["Standard"].pricing_tier == "pricing_tier" diff --git a/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py b/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py index b1ace7cc62..93902e8eeb 100644 --- a/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py +++ b/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py @@ -75,6 +75,7 @@ class Test_compute_project_os_login_enabled: result[0].status_extended, ) assert result[0].resource_id == project.id + assert result[0].resource_name == project.id assert result[0].location == "global" assert result[0].project_id == GCP_PROJECT_ID @@ -124,5 +125,6 @@ class Test_compute_project_os_login_enabled: result[0].status_extended, ) assert result[0].resource_id == project.id + assert result[0].resource_name == project.id assert result[0].location == "global" assert result[0].project_id == GCP_PROJECT_ID diff --git a/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py b/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py index de6a2ddc6a..3791846a55 100644 --- a/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py +++ b/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py @@ -76,6 +76,7 @@ class Test_iam_audit_logs_enabled: r.status_extended, ) assert r.resource_id == GCP_PROJECT_ID + assert r.resource_name == GCP_PROJECT_ID assert r.project_id == GCP_PROJECT_ID assert r.location == cloudresourcemanager_client.region @@ -125,5 +126,6 @@ class Test_iam_audit_logs_enabled: r.status_extended, ) assert r.resource_id == GCP_PROJECT_ID + assert r.resource_name == GCP_PROJECT_ID assert r.project_id == GCP_PROJECT_ID assert r.location == cloudresourcemanager_client.region From 62fbce0b5efdc6cf7148ff48a53fe2249359cf27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 11:16:47 +0200 Subject: [PATCH 103/359] chore(deps): bump azure-identity from 1.19.0 to 1.21.0 (#7192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6c268d0b99..5dbb1b5739 100644 --- a/poetry.lock +++ b/poetry.lock @@ -335,14 +335,14 @@ aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -version = "1.19.0" +version = "1.21.0" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81"}, - {file = "azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83"}, + {file = "azure_identity-1.21.0-py3-none-any.whl", hash = "sha256:258ea6325537352440f71b35c3dffe9d240eae4a5126c1b7ce5efd5766bd9fd9"}, + {file = "azure_identity-1.21.0.tar.gz", hash = "sha256:ea22ce6e6b0f429bc1b8d9212d5b9f9877bd4c82f1724bfa910760612c07a9a6"}, ] [package.dependencies] @@ -5338,4 +5338,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "d711bb44227117b377d4b211a072d596a74ae8a53f883f8c786c1743d5241db6" +content-hash = "8e144436168ed83fa96186d70f93bf92547c434856da1e7be41410de81a40aa2" diff --git a/pyproject.toml b/pyproject.toml index 864a88509e..1cdf0b8ce0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ classifiers = [ dependencies = [ "awsipranges==0.3.3", "alive-progress==3.2.0", - "azure-identity==1.19.0", + "azure-identity==1.21.0", "azure-keyvault-keys==4.10.0", "azure-mgmt-applicationinsights==4.1.0", "azure-mgmt-authorization==4.0.0", From 2b0a3144c734c504da52d31b26574c596261c466 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Wed, 2 Apr 2025 15:59:08 +0200 Subject: [PATCH 104/359] chore(regions_update): Changes in regions for AWS services (#7417) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 1 + 1 file changed, 1 insertion(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index d5adfbc258..2e2a3f8398 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -5099,6 +5099,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", From d8dce07019c136c5c57728d0301f11739cdd43ee Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 3 Apr 2025 15:31:13 +0545 Subject: [PATCH 105/359] chore(deletion): Add environment variable for batch size (#7423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Víctor Fernández Poyatos --- api/.env.example | 3 +++ api/CHANGELOG.md | 1 + api/src/backend/api/db_utils.py | 2 +- api/src/backend/config/django/base.py | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/api/.env.example b/api/.env.example index cf347b93c3..76ea6de3d2 100644 --- a/api/.env.example +++ b/api/.env.example @@ -53,3 +53,6 @@ DJANGO_GOOGLE_OAUTH_CALLBACK_URL="" DJANGO_GITHUB_OAUTH_CLIENT_ID="" DJANGO_GITHUB_OAUTH_CLIENT_SECRET="" DJANGO_GITHUB_OAUTH_CALLBACK_URL="" + +# Deletion Task Batch Size +DJANGO_DELETION_BATCH_SIZE=5000 diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index db0d696488..a8a2c7cf75 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to the **Prowler API** are documented in this file. ### Fixed - Added duplicated scheduled scans handling ([#7401])(https://github.com/prowler-cloud/prowler/pull/7401). +- Added environment variable to configure the deletion task batch size ([#7423])(https://github.com/prowler-cloud/prowler/pull/7423). --- diff --git a/api/src/backend/api/db_utils.py b/api/src/backend/api/db_utils.py index f36c2ef05c..63a7769c25 100644 --- a/api/src/backend/api/db_utils.py +++ b/api/src/backend/api/db_utils.py @@ -106,7 +106,7 @@ def generate_random_token(length: int = 14, symbols: str | None = None) -> str: return "".join(secrets.choice(symbols or _symbols) for _ in range(length)) -def batch_delete(tenant_id, queryset, batch_size=5000): +def batch_delete(tenant_id, queryset, batch_size=settings.DJANGO_DELETION_BATCH_SIZE): """ Deletes objects in batches and returns the total number of deletions and a summary. diff --git a/api/src/backend/config/django/base.py b/api/src/backend/config/django/base.py index 7ce3e8c63c..876bd6096c 100644 --- a/api/src/backend/config/django/base.py +++ b/api/src/backend/config/django/base.py @@ -241,3 +241,5 @@ DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION = env.str("DJANGO_OUTPUT_S3_AWS_DEFAULT_REGI SECURE_CONTENT_TYPE_NOSNIFF = True X_FRAME_OPTIONS = "DENY" SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin" + +DJANGO_DELETION_BATCH_SIZE = env.int("DJANGO_DELETION_BATCH_SIZE", 5000) From 41e576f4f1a1ca2d5b1c7e595f3982f901f4b0b4 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Thu, 3 Apr 2025 09:37:46 -0400 Subject: [PATCH 106/359] fix(gcp): make logging sink check at project level (#7421) --- .../logging_sink_created.py | 26 +++++++++---------- .../logging_sink_created_test.py | 15 ++++++++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/prowler/providers/gcp/services/logging/logging_sink_created/logging_sink_created.py b/prowler/providers/gcp/services/logging/logging_sink_created/logging_sink_created.py index 3905332e96..d180a211ca 100644 --- a/prowler/providers/gcp/services/logging/logging_sink_created/logging_sink_created.py +++ b/prowler/providers/gcp/services/logging/logging_sink_created/logging_sink_created.py @@ -5,23 +5,13 @@ from prowler.providers.gcp.services.logging.logging_client import logging_client class logging_sink_created(Check): def execute(self) -> Check_Report_GCP: findings = [] - projects_with_sink = set() + projects_with_logging_sink = {} for sink in logging_client.sinks: - report = Check_Report_GCP( - metadata=self.metadata(), - resource=sink, - location=logging_client.region, - ) - projects_with_sink.add(sink.project_id) - report.status = "FAIL" - report.status_extended = f"Sink {sink.name} is enabled but not exporting copies of all the log entries in project {sink.project_id}." if sink.filter == "all": - report.status = "PASS" - report.status_extended = f"Sink {sink.name} is enabled exporting copies of all the log entries in project {sink.project_id}." - findings.append(report) + projects_with_logging_sink[sink.project_id] = sink for project in logging_client.project_ids: - if project not in projects_with_sink: + if project not in projects_with_logging_sink.keys(): report = Check_Report_GCP( metadata=self.metadata(), resource=logging_client.projects[project], @@ -31,5 +21,13 @@ class logging_sink_created(Check): report.status = "FAIL" report.status_extended = f"There are no logging sinks to export copies of all the log entries in project {project}." findings.append(report) - + else: + report = Check_Report_GCP( + metadata=self.metadata(), + resource=projects_with_logging_sink[project], + location=logging_client.region, + ) + report.status = "PASS" + report.status_extended = f"Sink {projects_with_logging_sink[project].name} is enabled exporting copies of all the log entries in project {project}." + findings.append(report) return findings diff --git a/tests/providers/gcp/services/logging/logging_sink_created/logging_sink_created_test.py b/tests/providers/gcp/services/logging/logging_sink_created/logging_sink_created_test.py index 7ad8f9a51f..9392efb625 100644 --- a/tests/providers/gcp/services/logging/logging_sink_created/logging_sink_created_test.py +++ b/tests/providers/gcp/services/logging/logging_sink_created/logging_sink_created_test.py @@ -146,6 +146,15 @@ class Test_logging_sink_created: project_id=GCP_PROJECT_ID, ) ] + logging_client.projects = { + GCP_PROJECT_ID: GCPProject( + id=GCP_PROJECT_ID, + number="123456789012", + name="test", + labels={}, + lifecycle_state="ACTIVE", + ) + } check = logging_sink_created() result = check.execute() @@ -153,9 +162,9 @@ class Test_logging_sink_created: assert result[0].status == "FAIL" assert ( result[0].status_extended - == f"Sink sink1 is enabled but not exporting copies of all the log entries in project {GCP_PROJECT_ID}." + == f"There are no logging sinks to export copies of all the log entries in project {GCP_PROJECT_ID}." ) - assert result[0].resource_id == "sink1" - assert result[0].resource_name == "sink1" + assert result[0].resource_id == GCP_PROJECT_ID + assert result[0].resource_name == "test" assert result[0].project_id == GCP_PROJECT_ID assert result[0].location == GCP_EU1_LOCATION From 32021847186e64d050613e9c907128d607f8bda5 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Thu, 3 Apr 2025 15:39:00 +0200 Subject: [PATCH 107/359] chore(regions_update): Changes in regions for AWS services (#7424) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 2e2a3f8398..f161c75ea6 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -5204,6 +5204,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", "ca-central-1", "ca-west-1", "eu-central-1", @@ -6756,6 +6757,7 @@ "eu-west-1", "eu-west-2", "eu-west-3", + "me-central-1", "me-south-1", "sa-east-1", "us-east-1", From e4d234fe030c0a42a6bfa46afc597030cd427e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 3 Apr 2025 17:35:02 +0200 Subject: [PATCH 108/359] fix(azure): remove `resource_name` inside the `Check_Report` (#7420) --- .../defender_ensure_defender_for_databases_is_on.py | 1 - .../compute_project_os_login_enabled.py | 3 +-- .../iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py | 3 +-- .../defender_ensure_defender_for_databases_is_on_test.py | 4 ++-- .../compute_project_os_login_enabled_test.py | 4 ++-- .../iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py | 4 ++-- 6 files changed, 8 insertions(+), 11 deletions(-) diff --git a/prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.py b/prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.py index 7ae6fa9a9b..21f43a7e13 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.py +++ b/prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.py @@ -16,7 +16,6 @@ class defender_ensure_defender_for_databases_is_on(Check): metadata=self.metadata(), resource=pricings["SqlServers"] ) report.subscription = subscription - report.resource_name = "Defender plan Databases" report.status = "PASS" report.status_extended = f"Defender plan Defender for Databases from subscription {subscription} is set to ON (pricing tier standard)." if ( diff --git a/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py b/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py index 4d168ad7b8..4ed96e036e 100644 --- a/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py +++ b/prowler/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled.py @@ -8,8 +8,7 @@ class compute_project_os_login_enabled(Check): for project in compute_client.compute_projects: report = Check_Report_GCP( metadata=self.metadata(), - resource=project, - resource_name=project.id, + resource=compute_client.projects[project.id], project_id=project.id, location=compute_client.region, ) diff --git a/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py b/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py index a07758aa20..bec0cb851f 100644 --- a/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py +++ b/prowler/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled.py @@ -10,8 +10,7 @@ class iam_audit_logs_enabled(Check): for project in cloudresourcemanager_client.cloud_resource_manager_projects: report = Check_Report_GCP( metadata=self.metadata(), - resource=project, - resource_name=project.id, + resource=cloudresourcemanager_client.projects[project.id], project_id=project.id, location=cloudresourcemanager_client.region, ) diff --git a/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py index c4b6d641d4..354025d4b6 100644 --- a/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on_test.py @@ -214,7 +214,7 @@ class Test_defender_ensure_defender_for_databases_is_on: == f"Defender plan Defender for Databases from subscription {AZURE_SUBSCRIPTION_ID} is set to ON (pricing tier standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Databases" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id def test_defender_databases_cosmosdb_not_standard(self): @@ -272,5 +272,5 @@ class Test_defender_ensure_defender_for_databases_is_on: == f"Defender plan Defender for Databases from subscription {AZURE_SUBSCRIPTION_ID} is set to OFF (pricing tier not standard)." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Defender plan Databases" + assert result[0].resource_name == "Defender plan Servers" assert result[0].resource_id == resource_id diff --git a/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py b/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py index 93902e8eeb..abfd4ea361 100644 --- a/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py +++ b/tests/providers/gcp/services/compute/compute_project_os_login_enabled/compute_project_os_login_enabled_test.py @@ -75,7 +75,7 @@ class Test_compute_project_os_login_enabled: result[0].status_extended, ) assert result[0].resource_id == project.id - assert result[0].resource_name == project.id + assert result[0].resource_name == "test" assert result[0].location == "global" assert result[0].project_id == GCP_PROJECT_ID @@ -125,6 +125,6 @@ class Test_compute_project_os_login_enabled: result[0].status_extended, ) assert result[0].resource_id == project.id - assert result[0].resource_name == project.id + assert result[0].resource_name == "test" assert result[0].location == "global" assert result[0].project_id == GCP_PROJECT_ID diff --git a/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py b/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py index 3791846a55..1056b4f055 100644 --- a/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py +++ b/tests/providers/gcp/services/iam/iam_audit_logs_enabled/iam_audit_logs_enabled_test.py @@ -76,7 +76,7 @@ class Test_iam_audit_logs_enabled: r.status_extended, ) assert r.resource_id == GCP_PROJECT_ID - assert r.resource_name == GCP_PROJECT_ID + assert r.resource_name == "test" assert r.project_id == GCP_PROJECT_ID assert r.location == cloudresourcemanager_client.region @@ -126,6 +126,6 @@ class Test_iam_audit_logs_enabled: r.status_extended, ) assert r.resource_id == GCP_PROJECT_ID - assert r.resource_name == GCP_PROJECT_ID + assert r.resource_name == "test" assert r.project_id == GCP_PROJECT_ID assert r.location == cloudresourcemanager_client.region From 5e9d4a80a1ecccd4917c09600aa2d5672e8ddc6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 11:27:39 +0200 Subject: [PATCH 109/359] chore(deps): bump msgraph-sdk from 1.18.0 to 1.23.0 (#7128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico --- poetry.lock | 51 ++++++++++++++++++++++++-------------------------- pyproject.toml | 2 +- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5dbb1b5739..3f86152cdf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2521,21 +2521,21 @@ opentelemetry-sdk = ">=1.27.0" [[package]] name = "microsoft-kiota-http" -version = "1.3.4" -description = "Kiota http request adapter implementation for httpx library" +version = "1.9.2" +description = "Core abstractions for kiota generated libraries in Python" optional = false -python-versions = "*" +python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_http-1.3.4-py2.py3-none-any.whl", hash = "sha256:fb7eb9222550b671aa5279fd8701c968b41de2133a6367bd213495f6aae9fbf1"}, - {file = "microsoft_kiota_http-1.3.4.tar.gz", hash = "sha256:0ba94a5e982575f5a349b71a87aae2e01ff1722cfc0902247b7ef0a9072c1580"}, + {file = "microsoft_kiota_http-1.9.2-py3-none-any.whl", hash = "sha256:3a2d930a70d0184d9f4848473f929ee892462cae1acfaf33b2d193f1828c76c2"}, + {file = "microsoft_kiota_http-1.9.2.tar.gz", hash = "sha256:2ba3d04a3d1d5d600736eebc1e33533d54d87799ac4fbb92c9cce4a97809af61"}, ] [package.dependencies] -httpx = {version = ">=0.23.0", extras = ["http2"]} -microsoft-kiota_abstractions = ">=1.0.0,<2.0.0" -opentelemetry-api = ">=1.20.0" -opentelemetry-sdk = ">=1.20.0" +httpx = {version = ">=0.25,<1.0.0", extras = ["http2"]} +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" +opentelemetry-api = ">=1.27.0" +opentelemetry-sdk = ">=1.27.0" [[package]] name = "microsoft-kiota-serialization-form" @@ -2840,47 +2840,44 @@ portalocker = ">=1.4,<3" [[package]] name = "msgraph-core" -version = "1.2.0" +version = "1.3.2" description = "Core component of the Microsoft Graph Python SDK" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msgraph_core-1.2.0-py3-none-any.whl", hash = "sha256:4ce14bbe743c0f2dd8b53c7fcd338fc14081e0df6b14021f0d0e4bb63cd5a840"}, - {file = "msgraph_core-1.2.0.tar.gz", hash = "sha256:a4e42f692e664c60d63359e610bbf990f57b42d8080417261ff7042bbd59c98b"}, + {file = "msgraph_core-1.3.2-py3-none-any.whl", hash = "sha256:96d3d1ad1d2bc3d1d5eb76599e18cb699ccc78781b3492702b2f23ec8f22ae6e"}, + {file = "msgraph_core-1.3.2.tar.gz", hash = "sha256:d23964bfb20f636874ef875a984f5ab9e48fc4854f1530c6e4a617b84d59777d"}, ] [package.dependencies] httpx = {version = ">=0.23.0", extras = ["http2"]} -microsoft-kiota-abstractions = ">=1.0.0,<2.0.0" -microsoft-kiota-authentication-azure = ">=1.0.0,<2.0.0" -microsoft-kiota-http = ">=1.0.0,<2.0.0" +microsoft-kiota-abstractions = ">=1.8.0,<2.0.0" +microsoft-kiota-authentication-azure = ">=1.8.0,<2.0.0" +microsoft-kiota-http = ">=1.8.0,<2.0.0" [package.extras] dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"] [[package]] name = "msgraph-sdk" -version = "1.18.0" +version = "1.23.0" description = "The Microsoft Graph Python SDK" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msgraph_sdk-1.18.0-py3-none-any.whl", hash = "sha256:f09b015bb9d7690bc6f30c9a28f9a414107aaf06be4952c27b3653dcdf33f2a3"}, - {file = "msgraph_sdk-1.18.0.tar.gz", hash = "sha256:ef49166ada7b459b5a843ceb3d253c1ab99d8987ebf3112147eb6cbcaa101793"}, + {file = "msgraph_sdk-1.23.0-py3-none-any.whl", hash = "sha256:58e0047b4ca59fd82022c02cd73fec0170a3d84f3b76721e3db2a0314df9a58a"}, + {file = "msgraph_sdk-1.23.0.tar.gz", hash = "sha256:6dd1ba9a46f5f0ce8599fd9610133adbd9d1493941438b5d3632fce9e55ed607"}, ] [package.dependencies] azure-identity = ">=1.12.0" -microsoft-kiota-abstractions = ">=1.3.0,<2.0.0" -microsoft-kiota-authentication-azure = ">=1.0.0,<2.0.0" -microsoft-kiota-http = ">=1.0.0,<2.0.0" -microsoft-kiota-serialization-form = ">=0.1.0" -microsoft-kiota-serialization-json = ">=1.3.0,<2.0.0" -microsoft-kiota-serialization-multipart = ">=0.1.0" -microsoft-kiota-serialization-text = ">=1.0.0,<2.0.0" -msgraph_core = ">=1.0.0" +microsoft-kiota-serialization-form = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-json = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-multipart = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-text = ">=1.8.0,<2.0.0" +msgraph_core = ">=1.3.1" [package.extras] dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"] @@ -5338,4 +5335,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "8e144436168ed83fa96186d70f93bf92547c434856da1e7be41410de81a40aa2" +content-hash = "be5328ab34647258a0ba8c9a7966b7abb38c842bd84238d242f05afec60cddbb" diff --git a/pyproject.toml b/pyproject.toml index 1cdf0b8ce0..2143b85db3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ dependencies = [ "jsonschema==4.23.0", "kubernetes==32.0.1", "microsoft-kiota-abstractions==1.9.2", - "msgraph-sdk==1.18.0", + "msgraph-sdk==1.23.0", "numpy==2.0.2", "pandas==2.2.3", "py-ocsf-models==0.3.1", From 0fd395ea83073b3ca16d5429fcac77a56405973b Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 4 Apr 2025 12:08:57 +0200 Subject: [PATCH 110/359] fix: correct fetch variable name from invitations to roles (#7437) --- ui/actions/roles/roles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index 8f7cbde0fb..5a03e22824 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -30,13 +30,13 @@ export const getRoles = async ({ }); try { - const invitations = await fetch(url.toString(), { + const roles = await fetch(url.toString(), { headers: { Accept: "application/vnd.api+json", Authorization: `Bearer ${session?.accessToken}`, }, }); - const data = await invitations.json(); + const data = await roles.json(); const parsedData = parseStringify(data); revalidatePath("/roles"); return parsedData; From 44174526d608d520dc6b13de3f75741c56426dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Fri, 4 Apr 2025 13:00:43 +0200 Subject: [PATCH 111/359] docs: add onboarding information step by step for each provider (#7362) --- docs/tutorials/aws/getting-started-aws.md | 214 ++++++++++++++++++ docs/tutorials/aws/img/add-account-id.png | Bin 0 -> 122749 bytes .../aws/img/assume-role-overview.png | Bin 0 -> 186148 bytes docs/tutorials/aws/img/aws-account-id.png | Bin 0 -> 45966 bytes docs/tutorials/aws/img/aws-cloudshell.png | Bin 0 -> 10345 bytes docs/tutorials/aws/img/cloudformation-nav.png | Bin 0 -> 53978 bytes docs/tutorials/aws/img/cloudshell-output.png | Bin 0 -> 176260 bytes .../aws/img/connect-via-credentials.png | Bin 0 -> 152485 bytes docs/tutorials/aws/img/create-stack.png | Bin 0 -> 100510 bytes .../aws/img/download-role-template.png | Bin 0 -> 130501 bytes docs/tutorials/aws/img/fill-stack-data.png | Bin 0 -> 463628 bytes .../aws/img/get-external-id-prowler-cloud.png | Bin 0 -> 79311 bytes docs/tutorials/aws/img/get-role-arn.png | Bin 0 -> 410582 bytes .../img/launch-scan-button-prowler-cloud.png | Bin 0 -> 284153 bytes .../aws/img/next-button-prowler-cloud.png | Bin 0 -> 19844 bytes .../aws/img/next-cloudformation-template.png | Bin 0 -> 20686 bytes .../aws/img/paste-role-arn-prowler.png | Bin 0 -> 540851 bytes .../img/prowler-cloud-credentials-next.png | Bin 0 -> 143966 bytes .../aws/img/prowler-cloud-external-id.png | Bin 0 -> 93181 bytes .../aws/img/prowler-scan-pre-info.png | Bin 0 -> 426215 bytes .../aws/img/prowler-scan-role-template.png | Bin 0 -> 251329 bytes docs/tutorials/aws/img/select-auth-method.png | Bin 0 -> 119583 bytes docs/tutorials/aws/img/select-aws.png | Bin 0 -> 122230 bytes .../aws/img/stack-creation-second-step.png | Bin 0 -> 439138 bytes docs/tutorials/aws/img/submit-third-page.png | Bin 0 -> 289928 bytes .../aws/img/upload-template-file.png | Bin 0 -> 115862 bytes .../img/upload-template-from-downloads.png | Bin 0 -> 115233 bytes docs/tutorials/azure/getting-started-azure.md | 171 ++++++++++++++ .../azure/img/add-api-permission.png | Bin 0 -> 217108 bytes .../add-credentials-azure-prowler-cloud.png | Bin 0 -> 135729 bytes .../azure/img/add-custom-role-json.png | Bin 0 -> 70282 bytes docs/tutorials/azure/img/add-custom-role.png | Bin 0 -> 70228 bytes docs/tutorials/azure/img/add-reader-role.png | Bin 0 -> 72283 bytes .../azure/img/add-role-assigment.png | Bin 0 -> 56534 bytes .../azure/img/add-subscription-id.png | Bin 0 -> 121290 bytes .../azure/img/api-permissions-page.png | Bin 0 -> 66921 bytes .../azure/img/api-permissions-result.png | Bin 0 -> 220718 bytes docs/tutorials/azure/img/app-overview.png | Bin 0 -> 129585 bytes .../azure/img/app-registration-menu.png | Bin 0 -> 84131 bytes .../application-permissions-inside-graph.png | Bin 0 -> 70676 bytes .../azure/img/certificates-and-secrets.png | Bin 0 -> 67741 bytes .../azure/img/click-add-permissions.png | Bin 0 -> 10898 bytes docs/tutorials/azure/img/click-next-azure.png | Bin 0 -> 5510 bytes .../azure/img/directory-permission.png | Bin 0 -> 84098 bytes .../azure/img/download-prowler-role.png | Bin 0 -> 207391 bytes .../azure/img/get-subscription-id.png | Bin 0 -> 83069 bytes .../azure/img/grant-admin-consent.png | Bin 0 -> 535164 bytes docs/tutorials/azure/img/iam-azure-page.png | Bin 0 -> 71564 bytes docs/tutorials/azure/img/launch-scan.png | Bin 0 -> 31461 bytes .../azure/img/member-select-app-prowler.png | Bin 0 -> 16789 bytes .../azure/img/microsoft-graph-detail.png | Bin 0 -> 99040 bytes .../tutorials/azure/img/new-client-secret.png | Bin 0 -> 122049 bytes docs/tutorials/azure/img/new-registration.png | Bin 0 -> 130252 bytes .../tutorials/azure/img/policy-permission.png | Bin 0 -> 93127 bytes .../azure/img/prowler-app-registration.png | Bin 0 -> 39174 bytes .../azure/img/review-and-assign-last-step.png | Bin 0 -> 12718 bytes .../tutorials/azure/img/review-and-create.png | Bin 0 -> 7557 bytes .../azure/img/search-microsoft-entra-id.png | Bin 0 -> 69169 bytes .../azure/img/search-subscriptions.png | Bin 0 -> 66414 bytes .../azure/img/select-azure-prowler-cloud.png | Bin 0 -> 122541 bytes .../azure/img/select-custom-role-prowler.png | Bin 0 -> 138173 bytes .../azure/img/select-members-iam.png | Bin 0 -> 61223 bytes .../azure/img/subscription-page-azure.png | Bin 0 -> 69384 bytes docs/tutorials/azure/img/user-permission.png | Bin 0 -> 90799 bytes docs/tutorials/gcp/getting-started-gcp.md | 107 +++++++++ docs/tutorials/gcp/img/access-console.png | Bin 0 -> 184418 bytes docs/tutorials/gcp/img/add-project-id.png | Bin 0 -> 129232 bytes .../gcp/img/authorize-cloud-shell.png | Bin 0 -> 48067 bytes docs/tutorials/gcp/img/copy-auth-code.png | Bin 0 -> 60621 bytes docs/tutorials/gcp/img/enter-auth-code.png | Bin 0 -> 66115 bytes .../img/enter-credentials-prowler-cloud.png | Bin 0 -> 49746 bytes .../gcp/img/get-needed-values-auth.png | Bin 0 -> 92094 bytes .../gcp/img/get-temp-file-credentials.png | Bin 0 -> 81876 bytes docs/tutorials/gcp/img/launch-scan.png | Bin 0 -> 31314 bytes docs/tutorials/gcp/img/open-link-console.png | Bin 0 -> 103533 bytes docs/tutorials/gcp/img/project-id-console.png | Bin 0 -> 103770 bytes docs/tutorials/gcp/img/run-gcloud-auth.png | Bin 0 -> 41308 bytes docs/tutorials/gcp/img/select-gcp.png | Bin 0 -> 137754 bytes docs/tutorials/gcp/img/take-account-email.png | Bin 0 -> 68096 bytes docs/tutorials/img/add-cloud-provider.png | Bin 0 -> 9493 bytes docs/tutorials/img/cloud-providers-page.png | Bin 0 -> 31891 bytes mkdocs.yml | 11 +- 82 files changed, 499 insertions(+), 4 deletions(-) create mode 100644 docs/tutorials/aws/getting-started-aws.md create mode 100644 docs/tutorials/aws/img/add-account-id.png create mode 100644 docs/tutorials/aws/img/assume-role-overview.png create mode 100644 docs/tutorials/aws/img/aws-account-id.png create mode 100644 docs/tutorials/aws/img/aws-cloudshell.png create mode 100644 docs/tutorials/aws/img/cloudformation-nav.png create mode 100644 docs/tutorials/aws/img/cloudshell-output.png create mode 100644 docs/tutorials/aws/img/connect-via-credentials.png create mode 100644 docs/tutorials/aws/img/create-stack.png create mode 100644 docs/tutorials/aws/img/download-role-template.png create mode 100644 docs/tutorials/aws/img/fill-stack-data.png create mode 100644 docs/tutorials/aws/img/get-external-id-prowler-cloud.png create mode 100644 docs/tutorials/aws/img/get-role-arn.png create mode 100644 docs/tutorials/aws/img/launch-scan-button-prowler-cloud.png create mode 100644 docs/tutorials/aws/img/next-button-prowler-cloud.png create mode 100644 docs/tutorials/aws/img/next-cloudformation-template.png create mode 100644 docs/tutorials/aws/img/paste-role-arn-prowler.png create mode 100644 docs/tutorials/aws/img/prowler-cloud-credentials-next.png create mode 100644 docs/tutorials/aws/img/prowler-cloud-external-id.png create mode 100644 docs/tutorials/aws/img/prowler-scan-pre-info.png create mode 100644 docs/tutorials/aws/img/prowler-scan-role-template.png create mode 100644 docs/tutorials/aws/img/select-auth-method.png create mode 100644 docs/tutorials/aws/img/select-aws.png create mode 100644 docs/tutorials/aws/img/stack-creation-second-step.png create mode 100644 docs/tutorials/aws/img/submit-third-page.png create mode 100644 docs/tutorials/aws/img/upload-template-file.png create mode 100644 docs/tutorials/aws/img/upload-template-from-downloads.png create mode 100644 docs/tutorials/azure/getting-started-azure.md create mode 100644 docs/tutorials/azure/img/add-api-permission.png create mode 100644 docs/tutorials/azure/img/add-credentials-azure-prowler-cloud.png create mode 100644 docs/tutorials/azure/img/add-custom-role-json.png create mode 100644 docs/tutorials/azure/img/add-custom-role.png create mode 100644 docs/tutorials/azure/img/add-reader-role.png create mode 100644 docs/tutorials/azure/img/add-role-assigment.png create mode 100644 docs/tutorials/azure/img/add-subscription-id.png create mode 100644 docs/tutorials/azure/img/api-permissions-page.png create mode 100644 docs/tutorials/azure/img/api-permissions-result.png create mode 100644 docs/tutorials/azure/img/app-overview.png create mode 100644 docs/tutorials/azure/img/app-registration-menu.png create mode 100644 docs/tutorials/azure/img/application-permissions-inside-graph.png create mode 100644 docs/tutorials/azure/img/certificates-and-secrets.png create mode 100644 docs/tutorials/azure/img/click-add-permissions.png create mode 100644 docs/tutorials/azure/img/click-next-azure.png create mode 100644 docs/tutorials/azure/img/directory-permission.png create mode 100644 docs/tutorials/azure/img/download-prowler-role.png create mode 100644 docs/tutorials/azure/img/get-subscription-id.png create mode 100644 docs/tutorials/azure/img/grant-admin-consent.png create mode 100644 docs/tutorials/azure/img/iam-azure-page.png create mode 100644 docs/tutorials/azure/img/launch-scan.png create mode 100644 docs/tutorials/azure/img/member-select-app-prowler.png create mode 100644 docs/tutorials/azure/img/microsoft-graph-detail.png create mode 100644 docs/tutorials/azure/img/new-client-secret.png create mode 100644 docs/tutorials/azure/img/new-registration.png create mode 100644 docs/tutorials/azure/img/policy-permission.png create mode 100644 docs/tutorials/azure/img/prowler-app-registration.png create mode 100644 docs/tutorials/azure/img/review-and-assign-last-step.png create mode 100644 docs/tutorials/azure/img/review-and-create.png create mode 100644 docs/tutorials/azure/img/search-microsoft-entra-id.png create mode 100644 docs/tutorials/azure/img/search-subscriptions.png create mode 100644 docs/tutorials/azure/img/select-azure-prowler-cloud.png create mode 100644 docs/tutorials/azure/img/select-custom-role-prowler.png create mode 100644 docs/tutorials/azure/img/select-members-iam.png create mode 100644 docs/tutorials/azure/img/subscription-page-azure.png create mode 100644 docs/tutorials/azure/img/user-permission.png create mode 100644 docs/tutorials/gcp/getting-started-gcp.md create mode 100644 docs/tutorials/gcp/img/access-console.png create mode 100644 docs/tutorials/gcp/img/add-project-id.png create mode 100644 docs/tutorials/gcp/img/authorize-cloud-shell.png create mode 100644 docs/tutorials/gcp/img/copy-auth-code.png create mode 100644 docs/tutorials/gcp/img/enter-auth-code.png create mode 100644 docs/tutorials/gcp/img/enter-credentials-prowler-cloud.png create mode 100644 docs/tutorials/gcp/img/get-needed-values-auth.png create mode 100644 docs/tutorials/gcp/img/get-temp-file-credentials.png create mode 100644 docs/tutorials/gcp/img/launch-scan.png create mode 100644 docs/tutorials/gcp/img/open-link-console.png create mode 100644 docs/tutorials/gcp/img/project-id-console.png create mode 100644 docs/tutorials/gcp/img/run-gcloud-auth.png create mode 100644 docs/tutorials/gcp/img/select-gcp.png create mode 100644 docs/tutorials/gcp/img/take-account-email.png create mode 100644 docs/tutorials/img/add-cloud-provider.png create mode 100644 docs/tutorials/img/cloud-providers-page.png diff --git a/docs/tutorials/aws/getting-started-aws.md b/docs/tutorials/aws/getting-started-aws.md new file mode 100644 index 0000000000..840069a5e3 --- /dev/null +++ b/docs/tutorials/aws/getting-started-aws.md @@ -0,0 +1,214 @@ +# Getting Started with AWS on Prowler Cloud + + + +Set up your AWS account to enable security scanning using Prowler Cloud. + +## Requirements + +To configure your AWS account, you’ll need: + +1. Access to Prowler Cloud +2. Properly configured AWS credentials (either static or via an assumed IAM role) + +--- + +## Step 1: Get Your AWS Account ID + +1. Log in to the [AWS Console](https://console.aws.amazon.com) +2. Locate your AWS account ID in the top-right dropdown menu + +![Account ID detail](./img/aws-account-id.png) + +--- + +## Step 2: Access Prowler Cloud + +1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) +2. Go to `Configuration` > `Cloud Providers` + + ![Cloud Providers Page](../img/cloud-providers-page.png) + +3. Click `Add Cloud Provider` + + ![Add a Cloud Provider](../img/add-cloud-provider.png) + +4. Select `Amazon Web Services` + + ![Select AWS Provider](./img/select-aws.png) + +5. Enter your AWS Account ID and optionally provide a friendly alias + + ![Add account ID](./img/add-account-id.png) + +6. Choose your preferred authentication method (next step) + + ![Select auth method](./img/select-auth-method.png) + +--- + +## Step 3: Set Up AWS Authentication + +Before proceeding, choose your preferred authentication mode: + +Credentials + +* Quick scan as current user ✅ +* No extra setup ✅ +* Credentials time out ❌ + +Assumed Role + +* Preferred Setup ✅ +* Permanent Credentials ✅ +* Requires access to create role ❌ + +--- + +### 🔐 Assume Role (Recommended) + +![Assume Role Overview](./img/assume-role-overview.png) + +This method grants permanent access and is the recommended setup for production environments. + +=== "CloudFormation" + + 1. Download the [Prowler Scan Role Template](https://raw.githubusercontent.com/prowler-cloud/prowler/refs/heads/master/permissions/templates/cloudformation/prowler-scan-role.yml) + + ![Prowler Scan Role Template](./img/prowler-scan-role-template.png) + + ![Download Role Template](./img/download-role-template.png) + + 2. Open the [AWS Console](https://console.aws.amazon.com), search for **CloudFormation** + + ![CloudFormation Search](./img/cloudformation-nav.png) + + 3. Go to **Stacks** and click `Create stack` > `With new resources (standard)` + + ![Create Stack](./img/create-stack.png) + + 4. In **Specify Template**, choose `Upload a template file` and select the downloaded file + + ![Upload a template file](./img/upload-template-file.png) + ![Upload file from downloads](./img/upload-template-from-downloads.png) + + 5. Click `Next`, provide a stack name and the **External ID** shown in the Prowler Cloud setup screen + + ![External ID](./img/prowler-cloud-external-id.png) + ![Stack Data](./img/fill-stack-data.png) + + 6. Acknowledge the IAM resource creation warning and proceed + + ![Stack Creation Second Step](./img/stack-creation-second-step.png) + + 7. Click `Submit` to deploy the stack + + ![Click on submit](./img/submit-third-page.png) + +=== "Terraform" + + To provision the scan role using Terraform: + + 1. Run the following commands: + + ```bash + terraform init + terraform plan + terraform apply + ``` + + 2. During `plan` and `apply`, you will be prompted for the **External ID**, which is available in the Prowler Cloud UI: + + ![Get External ID](./img/get-external-id-prowler-cloud.png) + + > 💡 Note: Terraform will use the AWS credentials of your default profile. + +--- + +### Finish Setup with Assume Role + +8. Once the role is created, go to the **IAM Console**, click on the `ProwlerScan` role to open its details: + + ![ProwlerScan role info](./img/prowler-scan-pre-info.png) + +9. Copy the **Role ARN** + + ![New Role Info](./img/get-role-arn.png) + +10. Paste the ARN into the corresponding field in Prowler Cloud + + ![Input the Role ARN](./img/paste-role-arn-prowler.png) + +11. Click `Next`, then `Launch Scan` + + ![Next button in Prowler Cloud](./img/next-button-prowler-cloud.png) + ![Launch Scan](./img/launch-scan-button-prowler-cloud.png) + +--- + +### 🔑 Credentials (Static Access Keys) + +You can also configure your AWS account using static credentials (not recommended for long-term use): + +![Connect via credentials](./img/connect-via-credentials.png) + +=== "Long term credentials" + + 1. Go to the [AWS Console](https://console.aws.amazon.com), open **CloudShell** + + ![AWS CloudShell](./img/aws-cloudshell.png) + + 2. Run: + + ```bash + aws iam create-access-key + ``` + + 3. Copy the output containing: + + - `AccessKeyId` + - `SecretAccessKey` + + ![CloudShell Output](./img/cloudshell-output.png) + + > ⚠️ Save these credentials securely and paste them into the Prowler Cloud setup screen. + +=== "Short term credentials (Recommended)" + + You can use your [AWS Access Portal](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtogetcredentials.html) or the CLI: + + 1. Retrieve short-term credentials for the IAM identity using this command: + + ```bash + aws sts get-session-token --duration-seconds 900 + ``` + + ???+ note + Check the aws documentation [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/sts_example_sts_GetSessionToken_section.html) + + 2. Copy the output containing: + + - `AccessKeyId` + - `SecretAccessKey` + + > Sample output: + ```json + { + "Credentials": { + "AccessKeyId": "ASIAIOSFODNN7EXAMPLE", + "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY", + "SessionToken": "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE", + "Expiration": "2020-05-19T18:06:10+00:00" + } + } + ``` + + > ⚠️ Save these credentials securely and paste them into the Prowler Cloud setup screen. + +Complete the form in Prowler Cloud and click `Next` + +![Filled credentials page](./img/prowler-cloud-credentials-next.png) + +Click `Launch Scan` + +![Launch Scan](./img/launch-scan-button-prowler-cloud.png) diff --git a/docs/tutorials/aws/img/add-account-id.png b/docs/tutorials/aws/img/add-account-id.png new file mode 100644 index 0000000000000000000000000000000000000000..bfded597a98e770be2cb740d6d77809dae2aaa82 GIT binary patch literal 122749 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%0Dq)M#U4U8xcu@d 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%0A1!_)KF$pp9G$vM>cMz&(V!loEMc}qG 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Ν06`a;IMuYKT@aEH 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 hnID{Nbr{oGrCukQcBUK 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 SWw!x8H?C@4Dfr#|{{H|pQEDFm literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/aws-account-id.png b/docs/tutorials/aws/img/aws-account-id.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7c96efc4f1a3eb5ada8cfad6afee765a95cacf GIT binary patch literal 45966 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 NbrntJJSF2-{|EB$GmiiO literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/cloudformation-nav.png b/docs/tutorials/aws/img/cloudformation-nav.png new file mode 100644 index 0000000000000000000000000000000000000000..3ea375a34cbd5cbf77472a697f2b85f9f459220f GIT binary patch literal 53978 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 z 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 E4{``nhX4Qo literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/cloudshell-output.png b/docs/tutorials/aws/img/cloudshell-output.png new file mode 100644 index 0000000000000000000000000000000000000000..85a849372497a12dbf39e7fa52c51e5173e901a1 GIT binary patch literal 176260 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 z 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�AbLsQv?n{6!?Y@9P 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

EwrCB3b7JNUc%& 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∨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

=`*i9R%6zxiznPez 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 b{!Q3hO%EVXTbOdOfS;Q3W2K^prUCy0{18xn literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/fill-stack-data.png b/docs/tutorials/aws/img/fill-stack-data.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7214f0be5135e1363d3ee953ccfff18d569710 GIT binary patch literal 463628 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 z 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

C~Mt`94f+pUe5&+hk>iY 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%0D{lSh~}>7=iGlUFOEdE$59TBBb(W< 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

c=W{jnLZ_8!SIQ4n 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�-a!F05- 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

AO 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

;cyVZlJ-(n9ShQ&4@FLzSf`8!67*@Y85UY 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%0D)LxoA(eZAmk`>g3$=w)@d$ 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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/launch-scan-button-prowler-cloud.png b/docs/tutorials/aws/img/launch-scan-button-prowler-cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..06b7e37a858fc623a95856a1524ff893dd2a0e22 GIT binary patch literal 284153 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%0Dn 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≫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�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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/next-button-prowler-cloud.png b/docs/tutorials/aws/img/next-button-prowler-cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..f41437c17ec957e2a32ef565df611b3c322e0caf GIT binary patch literal 19844 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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/next-cloudformation-template.png b/docs/tutorials/aws/img/next-cloudformation-template.png new file mode 100644 index 0000000000000000000000000000000000000000..1f646f90b805ef231d4a474c62086935c93012ce GIT binary patch literal 20686 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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/paste-role-arn-prowler.png b/docs/tutorials/aws/img/paste-role-arn-prowler.png new file mode 100644 index 0000000000000000000000000000000000000000..82d71653344db7738cad6a01aba1f39d1d5a3049 GIT binary patch literal 540851 zcmbSz19WBGvTkhK+_5^gZFZcFJ9g5sZL4FaV|HwGY}>Y-xBqj_z4wfVasKg=kv->{ zRkfyS&sFtRt%NHnNFu`F!GVB)AWBP#seph$cY%O_`@ui~TSPFM3_w6Y)h$Ftm83;Q zNt7JzzFSzEf`H&88ygrHNzqde85$ZG42{##z&X0AgoQ<^82I*dPmqk0fF!9)$uTn8 zBfwmN(i-|rmu{`HLrI``YhjzD3`H$Y*n}2oBoVAJxoIdd!>RJaZOKS8C_v5l`e~B4 z{EQ}O351x~^N8qDO;Oxk}_iGxG0@a4-F zMe#6-4g-TFpG1G*1bousx?q2Q!EAp+9XnwoWimcC+^$-T5?p-YB|dQkgbKlr&rkZ% z?(WV=|82YJ&(E$yV1p~{lvl1hG#n_gx1nb!1#h{6Z!GM?ylv=VB-jVU(*6kkm)Z96Eou% zrvICmv&HxShuB|~e~SHMUjOWl@2{KjC|S6fT5E|}*Z@}*I5Yt+ZVtYGbn|~u{%4^7 zl>F*s>L_Yw0~B-?_@8b0m+-$6|98QEbgB72T{3fXvHp9X|3>;Z(ZA-vqv&V>?9TA7 zMHFD>WBNbZ{>9J7^w$di+lv2lJO9xN+)n{GKBoWH4FNduHa=kx5Frq0F<~_~(6bKc zOu~U=b|0!qsRH_-pqVH~5pME06f&APvB5#m1-Fi_NyBp&-OHwjriT~1-I|SoK{0$y z{3uisAqY}{e;kSo^|3LTnBsEICwu6!3L@I!wpngPzOd(DV znp}Ea9reVt8`xWS-q~!7xJcsJ0?HQ%1W?iL|6FXHp-Az!ou#Y-S^2=E5&b~AxL`I_ zhDT&lRZB(yG%a!o*V|uZq|YQ_?Yg7^KMy?nszUro4PbD<{zl<@34`QWV!i}ZSm<}B06LFIXWtX5;WIKKbDeiV(pdySjI!ylu;ul==Rc47zbA&mEx5-C zTj}W2K@Ld4b5!5Qded#ARgshzQ!6!-hszG-YaATX8D9`uggdo7(#$UMVfX8)%cKB{ zf8OPfD|hiqHer`OCzGC(N@-{?X?zJ8<_x<6NHbDg%Y$WtCtN}wxa@I}#VbjA6Hg10 zwLeU=oY?&R@#S`+minp}tBCv}Lo4shu)0A670vyI!j4zOjk~F6xV1*?ZC$l!a=u~^TxTWe1}LY3CS>fnMidqo%NTCs zCOMh9HSp{g34N1>y$K*O(<`DV1ux`2y0&a9&tDlWnm>H2cHDU4mW<{Kqf7VP$Ec$A z&z&D=E=1zVqb)1^$+kf3{EeNv+-D8Nx#k1rb?BwQ(9rPR@Ew(G%jlsK4z>1qx~8V) z14u))XZF+&4qJLN*VNSX)$|R5X-?~?77?@dVWX$75UdasfzTb>&>$t_5X8g6S|DB^ zCIw^s@v)(CFY80~d-Q?{4B{j}vkk_ehO!?;N>(;e1#Q+|RU!YUe^5gtNeV&#C~7`q zR*)-f*jb&*29>OX1MY<^WV?I!ZZ94|fUHbp@>4M%+OD*Hbk$)1T@Ml3Wz~-2EGOPb zG2Qcq(%pmig3{fy=VBjl2GJm=$fvO(!9smAg9oAal6@k%h8D)Rf00P1Y8q;v4d170 zP|P(~mfmVU%r#-y=xwZhG=16VA@EW-IDk{Z!vZ_h$+#8sp+YP6+1bXc|9xlS0xBHE zE{lRSPp+bWCim?^?3XtTABQBwd@v^94pCQR7A{4&(hB@{ZC$f5a>4mRg0{fhjpo%! z*kEo1iLCgGr0L7e-0*C6vhnd9mBVnXm1Ldl6yGy`qO{r zD4KJ1hzrEq-M`R*+iv8y@@B8p-;rT_lquf7p}|~pViKdGZFBJJ9=Pxb{$Et6jO#ge z6Z(EK;lDm6|B%Tt04f*$)`RCoZq4THQk*%?C$gA}C9C53Bi}-v%gsc?N7(i<$wvBL z8pI6ID;0>7(dcehKm*jq*Lnq@E{1_x-u4L_er`k~hX4HVIV(3JaHEA{+I#CQ%)L08gw4$j$HHq}5wJM_e7j z&Pe*^(brPx6!|q*j?01o^@G7E#M)Ps1z?NW&2k=nzmvO7IU0X;Dr%yx+3m(IbTa}@ zZ~+<~;X8iK5u}|8fz3uzj$8vp3&)7B(~m`wq3`EO<&h3wv1wDK>%YtI7iW}6U2b%k zthe6RIqt)8d)&di{1#hJZo58wrKnYi0&kXOqNP=@Yj3WBQD3+BpRn%HNY_rL+IBBv z6W4oxxla`Eei>P5Jl#vy_?C?R=XP$~!)DlS-M+^ouPlb545eACb_>C4$;Uo@=G>YKgh(xs${ z9Pk4HA%mDh&?t~J40sV1HjbP@yloCsQ?nV11K<#}_UVTbMXBA4MM3?Gt#=y5K)HT1 z_SWQ?@R&G`Pi@@W3PPVVRghY;0Ccz>QTaK!HLW?Qqxbq zCaGn=MtM!u64c5QYDS1l)%oAi(>a-mwEZ9>>}jMzY$Yj(cywt#-0y6hOiMKr7X2pl zld7a-poU3*iocPdp*I+)WG-XNjY=kG^sNF zW6tR&iDu@PF_rsiWs{Isby9nKqKd9s5LM6jAj=vV+CHxC94MriX8#fASV-6_jOA9- za_f}_t*U0DD7kDlt#5AI)%J-*N!9TS1hiAp8Itzir~+(r}(+E2jOkeqOW;G)gRT();yFLG!<0O#c{oBM?fxrNjq8 zYRQpd-u+CJsw#&vNzE5=L`v6cm7C-ZNdhFCG!zHxQWS&F)F1$K>c~BoZ4ad76_FQE7%GHV?fnFyhPU||slD-zq^L=~k+G>@a4y{NmFkjvYAPLhiVc)1g7 z0Ppv(w4|MpT50oGQh+*;B{fV7;$W_Xa)V567NByE{nRA9H`xsJzHl1U$27yBCesRk zk-BLU%F6uKULx1=hrNtR^^{zx8qj>N5Mb(?j`8Qj*`+othv* zgmtx-hjS|L*L%q0PTDFp7fu;3==A1gk^5~*xU$F?#=dq6EyULKB4t@5kZJ`N%q@2n z+CMz3Mu6L_Ae>d1<#uJ3OjxYHXPN$G<5@;`yHj-Wx}G3t40snxCsNkb0o?IW6mkOz zwzVT4{Df3`WtN8lG}P2d&*>jM?kO{86K~{wpv(^+c zyWwpoE=D>-=0$#E{7x@yVJ*gvTiu|`jaI3deC}vqLU#e6bd<4OXtd?vAEK9i5ztjQ_;U)S1d!tUjm=%VBf7JrxoNcxgVIuTqt( zSF6LXd3!!elTMhZ=chOFJ}k@=QmiX!jAD%o0Umw=xqe!j_Uk0d4}WmIQS4;l20ZFCT2hFHB0#3E zXzJOW;uw@rLPTNxi10+yEhk?<7n?g;=;@CK6H}f{4`5C3rPW6w;3M&TJQEfqPL7H~ zh;q_CXzSK;ChZN|CU0O$Wz?djx>4ZT(ZPg$?IUF9evPd5X|w_^(pwOtdP_<_xb z*sL}UAIN8z&X=**IqXt$yWAu_l*BMaX%X_uJV1L_j%4Z)Udz~fkrk~$1w82{Z@8Dz zjVtv*mx(r1TWL<1mDBO>3}#?|>$B23?siSQmjv+u$3b5pj)zrR{n%bcf-*QY*_STrgg8zWhGbfxv`CYVdS+3pC_d?F{1T-PP{Ph&!qP(ho#N4WRHoPSl z>pqYa*CZMDnFI}Z_W{~#&+%bGZg#hQ2a;TPBJ?Qro5+3!x8wxq51+)OSR8@`SUFYC z4&R0^y-@n}+I}RjUN(!@)%Pr%(Bf~DH&Zg^P;T(rm%lzZW?Ef{poEktVh>#>mYAL{ z=-o{4UJmufVvSs*Q;`K2q{EUud`xb@8+FpLNrOHgZ`{YkM3__pPGFRi{0X#mvHjfy z-FftH6!wM>#(DSFA2(84oCMKmxDd-N5;muUd-_v$iUNe>47w^c5@tk0k&>==s}p(x zUt|-%j|wJ^gINH@$cz9+HF?gd#B<>x9kX;%Te8}nQcx;lW0O7i1+G$(Owg0Ml}79d_bWBpRJ zM$_LSAfhs`+zWPy7U=Z@Q*g_Dy}37i3DQhq^m>=d@w^ z^Zi|!Q*-Ifo@)UUDM>w}R?CTh0{!{?8_%B@qC|HRpO?F1QdPSQvS|Dgx?0H#D#SOO z`2}QYN*mE};jmHMmOLDf%ZX853i43oI86J|w|?}=k(>P-KeK{1Q_b8yNC#Vmn7iY7 zLI{p@ySG2FC*2dJd?XoA-|rp1xhvM4JzXcVSl-#USlmFlAEcX^9M726^cP#5`#p)! zpdC1mSME_%wqMiZLVKD8t`YH=#L1<51tJh~C^L_NZ@8ZS!&C4mP1LZAm4Z0Yk` zuvIZUr}>|iG6b~G(E0If{N`dusNt3jLsFZjh;r_8T1f4th{yI6}uZ9{Zb@vcQL1Ek*!=qKNMl z?axBm^-HIEVeiune?%M#`yPEwoaQzS8}i0F<6rGQ77*7%PLj*elj%g>Avzjdj9JDp z190wDTr10^%Ia~*rsbK{uthT*ANcf;{ z=r>y}c{RBtTmpWrL9M~e#q~LU>;jpiwgOb66sfvogggzYw(G51-nlUnAuS#$DDUi{|C@ZDWHApQ-V&$ew} z7DG)yhOQ*3Of-#C_XB{t048>~<^Qf^r>NP{l!*PwqnGXbASb-Z{~@gDw8=kz(1w`bNk|L8(}YcMcd&6tx$V?5 zT<%XJ7t5;=xN4=`h*ORBR96TUYx%nVN4D$>Rh^jAGgtV$ER#)T20Y{CB65bbleiSabHc127you0@BKqE#X#LtZ>PE<}BkEjk_-?bYW^) zp+A$az3ifxwJSEAE<0F$oN2a);`Pb)T52_z)LJjsi6asAE5lx)IN)v2%EWCN;@W5! zb=Vrie7(ol;<{+@FVd?2J_B```K`la6jLKA-l_^0nWeqF)A##CChX~b;M|CJZfa)@ zMqk;g$~SOX=Dz^ZEibYur4407VdPm-0{4*MzI@UxA$hz2qT;~uSQJofD;VQ|pKK8P za-sIlIKYQ^@AQ;?jXBJ2g84rigYd8r&0o z9ZJXy*{=`h46d8rZEIe)ViY~9Q?f~DtmgMJmg%{jIKpX~zHXZxo*FF>0D^TM!S^}V zn;z&};fpL`sD!TWZr?bx^2x;kK4A~)=>aL5#G_Ha`@3k)4dCJSxZpW5Z&nMYAj0=k zJMrLlMnyP6F`GsF<>3M}fG^r;M-(B&LxB&cMLe>{XcD@qG;?fc95} zh+O*}@654V=UFZ~%#`;&09`pvjZ7-%rn|<&r65iw6EcP67seC)d2?tF`^kLubNG}< zlBzaJFKs}FNNv>zOS7MpwBi6Idi>g&uKSih(+DC?HPCH|vzYysKrxy!97D)k!@QrA zC{jy3B2T;~q^ieYTVe2ubP(@U!svLm#O&tF#klHft(;If>OQTnCY(z~FU|98>s5TOB>OtYH|8GtmiE@riMqjt8}4o&l-Ldvfu z1>gZP)_tYEOgX=BD}-78&6{>KQ8eP(*MmF()^({b1S!tW>z%I7=?}+pvxREh>?lGy z)rb=RM0j+BMXpVOi#u}j{6~qehfvIp+=c6A7NYAJRig@8V?ziLo4wzf?`H>#`%NQP z;HygI+UZu&v?V*96rW^Z7ZofvVtWC_{gZ<+1v#QyAVMa;Cz7r@bOwTyPkoj!bMlEe zL~?zZxlKhmh8SS>r3cP^ZV1)>ehrR=1b(vJa+*as%PaGFtF`Hp=JP3;X@ohG zY23jDY*(iK8A%EU{=PudMWqE3jC3k|H<4#X<)`gXIYK-~n^z}vKzU5o2%x$5BrBKx zt9B1v&tcbpNIg9TH*f1~Vn0QIyk1u~}TBSp){EhuaXq6{1Kk|Mv zq=8#Ivn<^fNXCxz2E*5K8+M`X?EZ=ULz(Ki<)4S6zExcgf2T4w;3$7Da&GzeA{9U& zU5Ns$#*8l(v?4}Zd`COzHe90z?Cttb4%jmrIMz_GOiBU>g|eE&;!xPFoMnQs*{452 z&3FSN)naiD$pltONy%^;Gx>hT<_nK5I;VQ%DGnMaZ26f6Ju}I2QfIkEX7F@~-#8qX zV6)%_<>R_*Y=hmVx{Cd8S2UJ59AY*%kP79?KU$0E$xrH8fiGI*x;3YAt zK|K}vfm|+Dx7lWHHOmYZqjCChJq3We`8znxiyCr<-CH}B4c7MN9@@9b9bTQAsD1qc z+Xmsr@r=m1MzW~y+mSHEr0A)2FrER;@{-n>K`?#pyc34->*!?vwdJsSPJHyw7FGN= zN}VR#WFWgv`v5M1pWK6t1n%ZIST#JVL)Yxob)SDG~WOaA=$=w%acFM`$Pf-qXQ?#QL)J^hahN zFWw&MM9u-LKomTn!}1n3Sh<0!;7=@Zpoip%Rv%z(<#!uKt6cEFql>-##>{?sh#g(t zGE;z+M*EJycvGlX=VUxWZ-;V$bIZ#KvrNjv*)kzAO(eG$qf8YK^{-gCqp~cspRp~y zI^KOVnBvdjWRez`>$B&)77_wh3k|>c?uwXl1!qW7DRiai4`-SB@6VLVpb=puP?}pr zU$JBytfTQcwIyQk7?-aKw>Vhm+66ntUfL4iLIiMFeViapZ^n-oDl_&D_Ka>J(%xQR zN}FU;8ChIT)S4-n5;eZLf5oELBzb;*Zf%jc2MP0uDT9L}o^6f~!H3grud`CK8Of9T zz1$-FxPg*jGMUYPv!G))40Jzb6cl2jx;*$MAiKmm1jS6}01A3L$yL%cqsD*pE7d&^ zDirjM4>=lsh(r>08jeL84sHvK5aP-A^TCy6cRXE2AhD*1q9K7tDe^7RQK?adnT#~- zMx^N!S>TCet%|cMKrn#C!T<5AcN%xCTqelykW^3lMxx>NIu_Q%aE(NVI?yb&Y({{- zCLE8zchs2{J2@BZ54%R=XIe*fYBvMbj(_oD9N)BnY8IMIIkjt+ux+!6Xs}*JxZmOy zaJX-)sI{Z|vne7Vb$i!oBvl&Ce}(OrvfciOX9FKp}QKD8&=K?bgGB|ZOH*VCI>JQ7OM-Gd)Qu7M!*i&1_< z-*-5QE_^Ue*p36v@6F7SKMXP-`VYdPzaT>+;gx=aI4Mya{jyL3C;fm)mqK@)<;tQc zZDZ?meVOq>U}#(moFa)sJw`gDalf%ifGN?)!_?j|Q?gL0ei^DLLbJMaFq!%{_(~yIL!?$3FxW@s^N=rzj(kj;s9QlDv}mO~3t#e9 zrAl8>!fCI0fbj|gn{{o5G`jKxpe`h~q7}26FqW&WStuijo^JPrO53JR*t@SO+P1jB zNwqM_IQPwZ7WHtp;izxEA`>JPji!vAabJ$|vYHJ8k%W|So!`U9tifeucqKR?=l4Z{ zx5?8>48K-tyFA_KyI2NgWPR}AR@pdi~|CsB?RxLL}!YuG=SJyT&Z9n4^>^l zUV?7nOZ$L%V#iwzO?rq_C_%gu0|>CA5% z9b6V?7>;eW8!am@n}jR|i{s-6vuODFFS{*9%A(gP=LD$KoMPPiZ<*nPlgc0NOzQCy z^MwP3e(l$*g%h6ey>J~H?b%kP^2<(@vm?0wDb#KsPZFoybzbUr-4um22&%e=T>~E( zvA5+9p5VF@)L^-x*&Qm&(hw;#MfSAP?7%9Ju|@grJa9s;h&OT9c~t1 zAz?!zwu~t~Ir&#X<{9p(=-x(xi}VK9$!}UsJ{<)7j%;qd1lOdPX6j9yh3pfZ7o?Rs zO*5f@_9II^JadxuX60f8d>&2h-{#@0RqpB>Xv(P4`iRXZcy5K}!iITgYc0?hI~wH! zZxNVuCYPPyjy#`$70-0Eus~?!fO}`VOok0r7FO2wQkWC~k@P%|W4mk428+c_^vywr zU7k-YDiQ0&Ddn@G^iw`N2YJKG#MoFuhFuFRgqtTyI)GgiDP*}EIX9Y_2+!1XWXdpb z>%$$PV#y(dU5#Awh|fT@RGmml^!^(IQ%Z zTcHFbO9N=WDqP=2HoFA~o4e*#=GR!+b`HNbUPL#o0TJ-kvn0&QbT`w8C z-Y+*t0%8Rc$lBpG>lneWiCIj-62?v!D&rBmU&nxvQ*hXCtrW4neXin0rPK^Rsj47W zaUgQ4%#R2R;SSXkfN-;vdbJiqfkbS`VG!dC1*b+zwdQf8y4$`4T&IY)k{UOT^V;*A zQ@iD6P0_b+Q%IWxbExj3bMAs!1q;4815+9VqH9~d7u#G1H3qtu1*J9m-eG&U(%5Gs z9OnB9yDTSKJzNhNU)Y%H&1C~ChI0Ce5vX8hlAM90Q?3@OI z>F59RvpSar;w1HLVP3xrgP;^;Ed+uqwRW8twlrvMA1jXLX1wXUKlN+Y*+wHi{KhrK znuE^(Q5fITz^m}t1_=P!A|oSdZvs6A>lV#zzqPGPBidn-=UJ@yT>Pn`4$pswbNV zN7Z`^Q9>gqEK|%Hfxd1P`Q~-~HB;k_C#>H1g5I#ka5%2XcKwI@VOEQ|XNWGpPleY* z{o_b-&5`X)65}{2r$iE(-9jIaSe+0bGQpBQClMg<>#X&dkcvMfdDxblBT9%^3x*4} zY>C48{vbZ3pIXp7=SYpF7mSLU!c+gD@jGBTBY?zb%YRZ@qE#yX=SP4E@?CTS2;bqF z&S}VuZWPN`9kI-XIrJrnLN+I6WWhtUr68b>K%xJ6=&MZV#n2iqG^2$6+N${)odK`% zrEMeUH5(xa{}JGfvicJz?cqAV=%!r%9SW-(z`ty6si=FW^GX8VeRsMjd(n1D6jlCO z(?X6}h&`#}>dr0T)mLifs;Sy!zN`}Cr=$_}{MHV260E43kyRzLV3_H0u>|V<0eQUM z*2MRA)yHBsLD1agnnir>#0h0p!e@$r&ms3}bG&pzY_GPSy@$X2n3J7U;?11kR;L5% ziU>9)%9yepeW;WCOU`I{(}PPkssYp0?yGS5Vk(r19`=Amp?f-RPpXqE=J&_glY6`p z%0HDS#A>+Ftgw%^yPnDRo zuxjVGtFEKU3## z(ia1jA83N@HXCJsa@ti97r*8{JM5a)*H9gM5q(RKC8mf>w?`5VtyUMykDE!jjz(Ux zMVo0bQ5-0SPIzfB(%`{7iI9CU}>&n>KzRI>PY)ZgX@d<=j$uZ zK@m#DF2z_({Vr3yghvcNaVs<_hk!A^zA+{gLudlyFS$Av*8P!MW7C_x;hXxLcij!& zPj8A&)f(v{2-{&}@lz@Bi6T&Ns4d-Rw#JtQ2cn^v_^%a7IU~GfF%99^PES{c%U!;L z2i;0zMHAP^sGPwn_Og_3T z4u9lvgn2L)b144=?UrycxP=`0gr-ief~;s%!cDO+7#YM#(4&NjSJanb8sYwp_$VLP zVb0rkASi#Dy7A8b`>ni{!kC75^nN?PW|7P7L`noLztEQta&I9*R>r&%HUUb#`E?u3 z>rYJ92^t>;sy?>**gfjvs5Goo?Rv?zu-hLTX}eE{{WMAJ17!hNfQ^GgJb{2C0$`Og zE{TwO&b#-F9;`P2S%~&n?+SBmDqn+`75-?J-D+Xz()TlM%-ff!KhH*UPf-QlnhcVr z)o=B^RA`JAqS}^5K_JHzMJ$-U84E zVlIfqSA0N;tmk-{H!=;6iNn4GtoEUq8E4M{MB4PNa3N#mRlCnK)GJ+*zrvg+Fk7b1 z`}Idlg|}x5#-YRIdcEYZdfB1lD@&tB+85`G%)kOjm1~8i>fH?Ej3=I`K%SGT5j-0C z4uxz!8mgF_Zi%eoR*O6dNOYEGhlDuYr&6dKCcXL6M4m}<5nzmdx4{BvD`9rE(#n*(|y$Kt>h9NzYf zG^hxd?ao(6n`z5ym#c2n=GAQS`tRcb6wKifY)J)5jA?!Rwc37xB*BonELiKZvWAt? zP#7;4>z+#4-Vc)rt1SiD;8piE0!e1ypnhlgYH4ZJ^iIsN{U(+0vWj@6g?bbp{l220 zn9d^2<7^!Y>3IMtt|-c`yBs;!p?k#zf$W|ES$^5+?QrnakI&`_D_5jSs<=Fz27*Pc zTIbBDYwUWqgi3iUYNR+R*`LS2Vz34Bd}!xIh(i}3Ja6s50uw2sxjz{XbiF|ybL;$> z9JZA&iq5F^V1HKa>z3n)%khR>qW~HYAePf2Zck-FY*~H~u~{wX@;G;gz(Jf{!$ev{ zyzabF)6_`2Y;s>&o>dJsiBr6{7Q8szM0-RN;{_SLe^G-9QD zmQtuwGLdDvHm^~B>Oy1|mz7n?b>4f8hQCmqx?FEI`rBqzC?rQEpYh^-OBmk7!+a@4 z(>shc>#>$@gZ0dgQ{kF~S*Z#xOh&jkw=<0ZK(PlyL7Lckt*MBDW2~jWQF1%NM%*A4 zxBU6T99Lhks-f&h2AEPAng6%6E+|v)jNLs_#nK`s6x}>QhC(KwAw#K2ph=R!VTZ)Q(o)y)dKdqzX`OPC@3n#eTDl7K#!K%TbO+RN z6cv>eExhaoc*_8NLs>D5z>DCG|;S zp)}y>WpdR+2W3hYt6^@?Fw$J*UrnZd`#OT$7!`(<0&tj~L7ckpK$k#h4oUQ$+AW zA-+|K?DU{PAn;$dU@YhK;_lzh61~Sd>?~P2yOZ`T70}6h%im&rQfaxI70x;=E!hm! z=AmY#CMH6PrzwESbcHdb0dTF+TtA{?j<3~K&1>zfhPN|R@SMvsY|yG^>$+^J zdDca|7w>m>@TZYt3(W}Z2=8$}RbL(ciL5oS1H@ncY_U4WXQyoOcO(I~qi!Yb;iM;V zf5R$@Fz3+|vh7r$10GH3E~KW3Nuf-A@iJFI+b?Y!-nS`PkVxXIz~&UF-4mYX%ZnVUKSk`UsztyiAv9FG&4 zI47zkgay`;QzhmRx`A%8+KH`W?!j;;7k?*S4i`WEL-<)E)A+$dGeV^%Tjwn(SfmsW z1ZF+u&_QKaiSH@88=sEuD0@cenmJu}Gn;#gzS`uWNJRa7cBFc(KjJg&I>jgDd@ouK zO*Wv3d*224#e#Y`vsMxjV#tF6tygkzGU3?aYCfFhUW~?U&e7MbP95$q2`MU{(JDZ& zDpiB?z~-dgJ2MyM?t2ic9VWFHsdsNrFo8*BRFQVF9;6Nh;(FbpW{pV_{)1fFx#%3b z6?#nyoc3-6`7Dj=rI9z(ypS3pXi=ik&t?Rv!bGW}^~cyQii3l>!r;*U5Fh!i{XU=X z$XBa1x=8ss&EbWa=bR~nx=A;@6Y{?S_Ttsd=J z^^2|HJrXjux6qmI#m8%rRVw36Kf0nc5g&%VF?RWP{wOCtM^(+Q{x3XP$_dv(W+PWN zl@)xPk=L9fI&N*xW3GbjrKOVSADyktWo}AJB&oZByWy8^DaL%i)AIx1_>2~#EYC0)ejQR$ zzT_mpv&4GMGgx$~ifn052iy_m@qBs78qigCoS&e(+hEW1;A!V#hCh5lQeC@dWwf_h_O7hjSerhV}_Xqpm z(ub+*pbuY|j5*k*7(S!9xhugQodWJq!zmkoSF5YAftx-PMHMe9u1#8TGA0;GXEFkz z!DKt%*HsxjpK~kyWMCH7cKZ{3R*o};{NrdOHbV;W`;+7i5W!GJ>TCT0Ol6tkCD_is z+l8P^*XWfVL++sv=#e~yR4;>`$v3O6ABcb$Jw~h@b!hdL%h=7G`N+u8|t0~8R`n8|boDN#kGcrXmaZA=DkFmZCCT>|kp z$uIr)J`Fbbo}VXu8Lbwo0#lQ;XeVPKM-C`SK`woU$XN=MH<s$iASWTzUMZHMA5MBC-J+izd*X4VM zaNXDa$G4igH}S#3=_(LA-*v%=cnZ6G+&-LZeh|!Nv{NtorcboL1*P9HrYu%d%+CMl zIcBZ#uqL1v3e{@h>U87y(PYa#QzRQxl~=xH!0;1W=HYaHPbLXRB)zxSXgH{R;Yz0OVg%1 zsSO+~SLF9Ta7Um)EOUcq$GAe5eLW68AT~4qP7l*XM6xarTi@v|n2-^6sfc039p-av z$22-9pW*MoBXG!LO&TRezMNK%U`+%*|Eq$F23=rR>)f;cjpBB4@PBI zo9j8XUYm1Nw9aRy+tqF;@-6}Nnn{n)$;f~gtiYd;@Lmwt5hCv=Q)cu_vhbp^D>!;G7;)EI$`&Ly?K0enHlud8ehMAZg5{ z4oPS7dhLjP^ZI__L!$kCp0e9$g=AJIxPJhzl z8lMp76++T>>~|$F+{tBCdf8EZI8%J7+*7FH{$am%3j6phxCHG@+@#pw4ztk(6YItQN?A}Ii@5^Uu`$Se)FOm;YI%uCEpa)FL!J+3zY1Nne_DyYEfsYSEd>ya6j-11 zm5f!N54JNh26`R9t_)kUkwgdGi6Zj@cz>M5ZN9xM0v$!9b^E+MW&kSjNPdQm_Mwv~ zD#MJb1BN8&-gKjzF3gEAIYqRCR~S32_l~Hpi$K10#W+g02Osyu;k4NtKj!4JK*G@( zLnrdGfB^aN=w?2~7&(+AP9L}wXt-hArW^8+L?etf0lqf0*pq-^2cVZ5gfAq6!$vLN zcdm4r#p$4pHpgb>fkg0?g>Yfl%NNT~&PvdNu{{Gkt5H!Y_;jK#CJBn*9!lAodzm>&hS5yCE3I;YY7%bfmVwXQark0}u zlrNl-?-WtP$Jn3lf<#&hZAY6C!a}!!5*8Tk<=ngR@eW#8(bB>lBEk$I&=oqM6_|0! z^7qhlng4nMCZHWpxb4??m35XY$c>*!L^{^rCS>n!L=j<>OOi~Mimq% zr*3Q7oR7(z4kr8?&p|1eot&KRD$Y2~+GzkmjdZ8gpp7YGk4T#qfImwq__oc$AE#X( zvOg}D3(lp%f9a@*U{Ck>fujDYu{l-GGvxvg=aS^#feK8znD%_UU=R&KN+w$OG}s+r zetz1Gy&no;xDru{XibvqZwmwL2En4=@z)TkkM)Hjr^XjZNRw8Wrqb(`nMGc1HYuKN zFaDJ+C`$UswWf93ep2i9`B$brFx7{W*!wPiEO7o3mhW~ipGk`D-B!GAR1lnMqI>eU#Tp^!BJB1JMLqG=K4p2tNjU~U&n zoq8!-EuD|x+nH^tyP9Di;7~(OTsoOA<}?jC#tfWPlCOqGHHI>8jQX8&2fZxbj~DAb zl+eGEK%J6|V}g~LR=ZO(5*EyxIyu>hJL41xCk$>^cr=4I-4FFVCi9&kKeaM*_?-^q zEWkUU5eZ5szmKKmWk65|nDV-u6dK!;WZ!ZnyVx6cxm_Fa8}-GO(-R2 zP7A@i^yqCt8dU*v7gubyc-L8ADoBhm{C|8OR<{C%&FzNQVL99CYA>&4u-xjUb)md` z?}+>xZrTv?5QNFyFR$L4y@eXAY7Iu5&x>inp=#fISxvJd!(}~47P^2Et=fi45h(?G z;muLkmS#VN>@1cnq_HRn2GP3l#{A|m^%#J^?)vFMRVor8)2z712_}44z4z5w75sJ~ zw?SLUj%L&ARR+MHX@Eyl1BVUroGy5xfy3!*Zu>|qrW&fYzGlM=&gjkA?UT^3LaU-H zfPEEpp#ZahgL0selUnS&gNO?XuZ_TurtD?5ezNDpGjh+6T&UPq;i^&1%XFOxwmQA- z4wE~PZIvRe%gUM>( zJ1Bh>X-rc-$euLmG3Fjs+?rhOVTZ99jFrz@?H^NcSVo0^-Q66C z0NDf31DJ_qEv@@r(8JJV675Y-yJFpi3znACiPi0St z3Lnq{41w&OgOj!y^n`LnwwHT-+&+$$DwFS(d_LzS#C|xeA6KN=LHzm*y!4hln8>25 zzZ?24^I!i9V8dH-)pb9O+3~#*d6f9$3VMzkAFID)jTg?Q81hp-k#c0+b#p)LJ{aDV zePWIX0qu?V^G4ogwc6)d*4mznhANggnIS`n3k$1z;HlE_X$y2cS1kaM3Yaa8v9&JS z&NWnnZUKtmB)Ge~2X_j0D4_77;MBgioo{#Tbz2)h zVa_4F_ou&~yzu1vxe(-O@7#lg+AN4UzTv4qvP7`}z?xs|9y7xPjp7Wfbf&nAwH^TV z{u6|saX@$?io+eRhfJx(jv&AsF*uEsGJ_2wee=)rrR%UXNY9~5rnFz?g{igjXoYTd zlhoe@`p_Ng+=fuS5LiH}i_}vvbbJ>0G8cNYHQ8b@(rn+aOf$5SorbbZwqV6Cu?LVJ$z1L5oFx0Zw-CPx2#2g83yTc4GmAbT<{_C3Dp3KH&bz>7t3 zWuh-@Pud25R~*xHH*fX+z_Z8qd&bU-Zul1wR)naH3@Xkh+vo~uzeIsF%hnRaxeD9n+svXC!q^)ZdOFO~DT{JWu_P5ZgH zn{-O8V6gNz|8VKCg`%Izh{{<^y?uBt%UYgg$^4ozsf7lfM@e_q0mNa~*Q z?bb?rfE^)QisemCW-+!iNKnMW-fI+ypuz4~g<^=r>Zl|ftCIV&N zlapU73%-HGU!|f2`J!`TN_&J1=#>GiMz1%S*8yxl(CzKnrRQ1tTIoyZ6%+~=}T z?Yx$4JN#w4udE$09|FOjo;-vc!V=j3d@hmIgq?S3pNz0OASR-a7x2u$T1#deWnfe1 zRX;ja894p-;XVFq0_Rm;zn6<_sV-4!XTZ%EL;6bDf#9Z3BJzipO`i%35)o;(f}*hc z_rXCFqCTfOz*84JJliWxwI1Z5C}2sZ0X-11^{`;^h6q!EA;!T~?5AH^#Ul9vE-H*t zYXUFMP6>j3Y`>82*E*RMb~=?_=`3*PEN!0`!GsK9VoLFhHrK6XvBKX(hF*qMf5Z{b z>~NPY(X)W}~m(oN%-D0Ddjh>UTjfV}OlTABOh90b(^Hj7F$kFZefx6D1cr4~v^ zjqB00Wag{wQl-0pd?f8329u(JK~e@&*FmzUb)aEP-YOslNTT~He$`79JmYy_B@W4U zNLi_M4%O{XB;{9meV7Rx?)l`Di)N0Kskq*l-0cq;ZM5O2`19M~>bBjD3% z$Nd`G%?8g54d`>8Bl4Bk)tn;7nA7$xVw_e63?zup*p0vu>v`Dnm=+ZW0W3iZ}a$ZCQUoc{EVBH)qe6f;QLpLyI`oQ7zGKKcKp zSpK(ul-{8TxMgv1_h9t(18-6Kdcl`RjLr-!TJ%IRL9~Zr^nD`nw-Ufa9@6e#{DAr* zy5lu|1-d8+W}~lJxRR6L9xO_+!i5?Hcoay2clgwr&)_q+# z3*8n6rp*rb&C%bYPts#JXW8R((dxD+dmCu z@rwoe0seyY4GbfCA}q2bcXP}yjo$c_`5ZS({nK&>U0vXR@a}svo*)eVc6FQlULJhd zhsTFc%>lw6jgxF*^k7;HjC5~}C;6Iq1WS)*j?Jq=$-NWDxao9TK zbFbrUL>)=sQj_A^c&m&4o@!#a9X=LxIJA2o3eI(U?$e`M`CSMt;m*l*(hcmo(@two zBdxwXlh%aF85V{)i|I2H;pf7Ww5T3VW+OkW#4f}T*Y+{Cyh9?JHi~$Ns#@m@^~%Mx zz5H~g|Bcq_CZVtC*|Js4s2J3hLE9PHLIO;L*@ign-6x@k3!(wwk(eQVxXF|$ew^+g}+W$r5IJ7gpy*>m|!O)O& z8f}k?GrJcmazQukS4htr>4*i{955kcWh2N)Dh(sRz&K&bwLK3-2`k?w-(&zSFuJ~> z!TfYVZ--=uoX!#)By8ZE4`1MmyR_7B)X4yv_9JD#NbCz)^OgzbL|O_}78RiQl(!{D zl}Pbbx7m)a>WdqHs3MqfN>46xgZ=nSZ@)|&`bSr11^}g4qfkAWlNz9~6WS(Y8`7ca zY;J4B>_o!|*Lyu!`FveS7IF{(e`}h*zt;(|sQpnUV4M?e@zIn(;!(Z_~9V2f6g?rODIid-1hnGnjX}u-EN0m z*&YC=D9S3vg3yRkBtuhKv^}?&O8mRMkqo`ss7LMWWWEe*`eG7;u$5_6C$1u^mE)^l zg98e{x7~b<`{`f+YvP80<<4#+)%!_XB+`)jD@8?Oj9R8jo{(HmH`M&~D|+5Q&k;Vf%e?qy2J5r(C$4Ci4w~2%Hsq%Iw{8ELBe;ndpZojRiVBep>y}-?=Ea zV7Ur*XZ~ZkCcXs4IE~drDP?I_zU|H>ZoAIo`Ibyva_8(%{A!YPal$O~_Uj&_J#RqD zP`I^nLxhwax?bu7w5##E=spY^LOG})+#sWh$r&X>{R^K1j!gr^%X*P1Fi z@9x)6w|viA>uL=FMMrXxQ1vp+8!g=u~Am<=YiQ-PFFUN)$hvxECrv9AnJ!l=Pa6K=ulcbnq%pxV-?IIV0 z8*tFlSK@Y5mltgR$(>Gx+$-X-+CX@bTo9EHn9Vxk27pev4tOUrH>slZmfYvRK7O@l zVC(ay=UX2YR6{C+a>{Ks3lL?~p2BN8dmgVOBQ%kZNSJb`1v9#XF1hLKJV9$!BR^^{ zF6l0|PUwEA5=e3z?GH-OZ3Fi3`Q;dvUXnz5_EY$JyW(Ml2Ss~g5|>k+II6>leEBJs z+ASuc$zc3ZVukU>86O+L6bJK!(8eK~R#QhAApvrGCupflm=DYDAGoIJjXKh-6B{a@ zdEXdkgjgtsnlWFc+msTD`k+OnU|T_z2XgWx6hQ+X<-eix3BqZeRzKHstLYPMZ`_kI zY?b?$9QlqEn_vW=KLl3;1Fvet|9#fwn*ZBYUjDrq#^@!Idl4AItMuyvHMbR`StAyO zqHTO^w_B|!-6aDXD4R_y$%Q@0HbbxboZlU^wuSGD@Z(&p)M-5W&NLjH{CJbH3-LNG z;5c#QpYae6yGOK1F8ldkAzb%*zuREw|BnqO1G3>z*3jA>_==&0{slAldD^S}xZhTwR>98@dcatR z%6ePfv*V)^16H^3o^~C8u6D}P{s@8lrD3MOeYneyrAVhEVli%hvR)RctH+F$3Wq(Ah*jSofIbqb#e?S`^s>~$`-QCj;-io*+hA@HFT4^YowH9U1QN05Ty z<;jj%TmTTzQ^GL7LWqwsE&}~XxV8==QdZT zmW{w$`5R@`8an#=U^O2iCB)J9fHp$7iMZ@J8g_Q-V9+7&;P8R3jy0KF*mGON?3Up9 z*JZs`r=S#CnF6GRSb(l? zNKC3?sVWVh?t`1EN(;#AFD;L}bc$4QISP?De=JG%SDM7TZ zS~Z3hHg;eOCwRkm1~5JC=&(5@(=OJRq5i@Tq>gneZ)=e8Nl;OeAi8=zxm4g<@6Jto z9=C<}l+1s~y6tAXB5l+X5{){M+FKUuM_qtp% z8^2e~%)fK4y_4-ZWW?TXvpqdr5;=qzV#+b?BpxajhccC&6bL)*Z!S9;YSA!r!XGi* zYhPe}2NH0US|K^mio5M>tS1445W))|igx;plTt+8-;^tXy<_jWZLg^So;0fW7eLe+ zgiPD_RnUjv4FEq#s&%zT#~_Jlm(0l_%x10;Z4^XMn%$zLO-e;e%o-}wd{ns0A$YUH7^ipMZgU~E3n??-9>->ao{2L$*n z1>1s(qafjbLx$`LJpJf160gTaB{xUnZv>aqM+1_!HNF@R2l~by#mqy493LP}ZtO3a z_?hFS@p?|x7eBRw`Uy_R-2zVuYYYUi zv`|)Jn=ER5`F&ZX$2;&;ygbgQT>!mK3{*!Lv7oEl9mQoY)}$YT1+1uY z(S$UG+%K_>aewq@xZoJRQANZ;8*|TA>io0NxW=nkYYi#ow3D+Qw?ncl6{Cce83>2`aJ#SF3uCz~%PE-})v}`B>~XpxbbS-65sD`q+YJ1rpyIVS6+sc(Izp!e8x=T!k}O8Q^wM7 zuYN=rnNUyv2=GUV>f}{_Cw^VB%V#ct?rju3Uru9iN@EY&5>-I33f&iim&9U4AN;X# z-(Eg5!8jzFWvNWcGA2tt{q=VV*GO-5UWY_^|E6G6b(8IKumGF7>8;=Kw{;?!qHIydlk!Foc>T>C9$YjW z(VW;em^xyeh({a=A|EsF9+0Qud2}{d)t^UB z5}D(&0hW|b=-zWD)za#$zgs$N6tko_9mFI*H>;`f1v(qrC>m@=oszqu znKJY6c{(qD{ITx2V|TNWOV+w(Sg=L$fl?5GT&02(B#B+oC~f&|((O~w)~TrcDJq4R z#9FVeC|32H{Glx31l1>Dg_?!1VA6u9L@`hKXXTVUtF)F7QfJlQ5$(3NPC2ZN*k!&h z4u;0!>g;1a!%f{$N+}Z}0~>oIM|PAYe_G&0iWUPuf9t`>U7Z52BVymx{e<)GCRY;i ze~yFUGKw>ovIn|d4fkII3q=WVfUF}xej+N~q%kvkZI1Pk0MifTq5pK)AkH=ICQ8^0 zC;*;m?`dUr@t0-FaSc_`@CT@~ogWF7Cv;t6cYr%b`z#{*@zn&mk)9#pWQB9D)|_G? zMp@yn@G$*++iZ}QuIJGaQOJULVb4UO_-mF=rjy0L#op8{LIJVt{2V6hDhg8c1sUFl z3v`Eb)Bi>R_R1vmmLmQTSV@@$I@{4*081^FY@{MwRdZ#;DUW5vzYdze`ddt*UE>N1wi4iO;go!>q;=Y2GtSAU*r;j&)U zVrn)cEBJwijUbHD(5w0*Mh7kDD($UqlMNjngUTFFh5R<4U!Q7K)^=WT`y}`>WA$k) zt2dX$ug9Wqt=(XKV*6v>;DN&^?dnJ#xnH8I5*Pr^sWToyt;s68+&ZAcneYrQ+QV6t zI0!k?%_wf_EqPK~?Xty+0)^Il&8m-%V95H$&Ia08=ZN#?JadU3ae_4xmteF5=9)wc zZkqfDJ|Zq6GzAr_ltPD0%}zas8qM8wq~`-Dd**bW@X2sA36EuY33pc(=jZUVI~bo# z&8CXx^mQRpyW6IiDzB1L(4t?ruBQKzW!V9=l<0Gq`=o>8TTW?L%e=ZH4&yD;D|Z zMtkh6V3i9DYg=vSD>*XOD#IqqN-qBv0(7 znN?8)Stw?j`WTz72EC4Il~M@9M9!Y_2gC&XT|E0DjRK_){p0ydhvdR;y^j0bRg?Cm zK_2BP(0^n{S@V*)+}4;gK%90hDhZ-eKV`*!clPDqw$e8wr@?pnSDxrVeSvBxo2=-%aI?AJ^4f45$>}W1<9ms3 z@`iy><@a-}ei52hQvORVKm**H9cY06oWk2+ZH2o@`)3+lGj^u#W~N4)`Nl7LCic8CuYl6_`oWnN@Upf1K3B{RY3qMN`VN%h7&yDKMaY(T=Sd)imG$q7wyF z(oUAE6{UMseW{6LMYMmd z3498q;yXwc8boQqK%XK8`_s`5DJ+0LELmhuQq-I z%VBFx93;ay3}k_IRgvkw5vhf~^JljDE+pUDmM`zR_mo1e+`G+JQn->;n zAbah60H*lvL`4M%@QdiN-)j&{KfQ6(xCa^R2#Ku^zsUs)W7tc!gi0d_Z%e9rtpRQ!7^K}^@yOxPgM19Q9P58A4ut2Lg9`g5Gg+s zF;kZ|a^?#-7wYo_bn5b^$}I!=nEO<*RYJoy;ndTu0N_sh3;Z|ER>K6>c~mTlkcTJs z#q9R$b2|X_=3mVT0rDvOij1lf27Nc--Nod#TiX6^nAi+yWIv3JpjZAiipj4scv$11 zJAE=LB1TyapRGdfKD~2#dqAM`^d&$SaONwpq~cjKcXdElKXa`6!YKC?Y;9I!D9Qvk z6DpqOI9u3;@$vJwwE=Q5exIZ;`dQT{k-gVEPs{PUWgwN=u>PMtOVLAkwn6zMSPky4 z?l;Z96`5J*!DYW_CaYio_aEEW?YgB&F~{(DB8@T?O)Mn8L=D0&Zfr2QaP!1Uof*uC zVSj8v+$@-%!0aMUE1>*ULE$zt{Zbj*bI~6CY3a0!rTVuMQm{U|Bx|EN05r~sW~qZMQjOV$+}&`)157s9G#e5)tqC`7{yHev zwfdF*erM%Wlf(ekX-DF`;YGeL_E-5)!584xr<}-5*?w60%trd5 zlY&2Zb}`hy?e=Y9zuBXF`<4*AO=VJGs*NJ~l6R)|5LOLdH(2^1<1P65F%?S?k6s@U z_tb`V=MT&2ZZKcB|6n*ZLmA>bv}R^p8h$b&yI9COeT@8!L?VvVTLyp{f5)2ymlty^Ehha?jCs2gqPMyP1220 z-Rn(Q^B21!8S^UsU3L2xIOvB?xeuoVBj`!`#Vp=roblWuXRA2V=Zfvfm-8Jhad0~d zg*Jzip5g4pUHjVZXgCgra++s;QQ^5i(P`7H^rFfWD5Y`F!2bE#mF>Q#g?r&3=Bk2I z+-}3bMZ@9vd`ht{W+v8wOrtM-Bsyp=prM{u0`slAo5h+yWy@}8^Z7;>qC=YMZeA)A zxiQoSa~O)93w_z?^!`b$a;As7eOo>YpHX>xE5WkmP3cF4`hnsbLgLc2S#>8aC{q1t zT`@4$zElnR9scj{wKL&ge3jB!)pgm^?1i!R?URR?Z@UN%2JhdQiD{AT1dv~D7yD*(Sh)S4-9%m6Yb&wMEm7NGQc$rfP>kyJ4Pi6)fO~TlCUOHdy!PT<*6mxy zD|I$lk^3nK&tQWfxE(gMMTd9B81f5abUBXBx4Ix-FesB*s);|Li@$1fX~a6%XU=EX z7eL&77* zG8aO#)Ll6WAtv`-)SN?iHCr4{r^;Iv$Xub4CYX^RGYBIxDO!LDsQbvbkj<5aBos;a zlX?rESC0uowqjD&Zcry!#fwRY4ZW@|%)J&%rEd`$lU^awoRCcFkj2=rl~Xce0n?Fx z3@4B>zzikNA1Bsu>-`OrMiJ8++SiLU0R%ZiTS3!$1fB^w@~I9BuVMi&tqEV3^DlEw zpC8IqceHQ1C_YF2wE11a^FW&<3FsT&YT_r|5MeU>cgF?aT0cYh z{@Xx>Z5o+v4TXRPemTaQ0U3iNzh$+ih!>p1%`jms7R6$jQ+1@JN*^wNWfZmmO&JJoCOgH>k}3 zFvJqZhwE)5z%p0OgbcvF&`fE;vD#bvaGu_;@gGZz;fYRE^F#`cqG38DS(vAueCUL0 z3S2O^{@H^XhkA`eu>O9ks#vlOM^~H-G>9{5Lh~u!G|JD*qkd-OCYu;5w}*KqUm8`=ssfn3mlHm`Fp8VwV{KQI;pIvsF7>S4QRA(;D>cH0Zpnx*hy^R zo8AJz%3l=Nu}H=AOSe3720mWw4kMzpGX$b$yui4HkdkW(HbwtcqQSKNxpOj$3vqao?r*=$`O^!eBKx@gYH=GkDqRqe z?qSLJ1x*3|mw#O%RV7-c31SZ$uH4AdU~tHIFT8M;D{7It6B}5G47n3@{^UN zALbDu|J}1}GC4wz?e-6-c|3KG-9Z~yAV5`K{{Q3gB#9(uu+Oj6=3bJ6K1uy#Fbp;c z4fnoJHbS!M+?7~c=g5YTIn1sB(>r7-GDB|F>&chR7*xhOpD0fRr`*zoT?RR^7iKM- z7@~*TlH!|O#~kL~ErqAL2Se*dC{WQFlwk=68z-Az=m@4^#UTQ}eQ4YLVFzD$>?2d{ zcqhJn+jnn)l;0TL?4DY8{4-zj`7U^KAsu8#bN84ET80tNc(wuh%KFEuDV|$^KUQw@ zG+Sj_>~wyT=_fG)@%C&ieKfD{wT-8PeYKM$YJcr{H_4yS_R446;H?q_b^Mj2v7Cii zi!cwAph}#ETIZrArzDrpjBhxPIrIOjxZ&7+9}*(Hc)jO+^NI=%cCE)H`}7qfI+HZH zupBOfUb&vLn*I-eu(-%;nq4TVPYMUEg8<+(sv>^jypV}Fk``;Z((n^%EgB7fOKc

J+l2(+zy$9rbtRv3Dc`+`z?pn^A?JDuSA`9IVz29Rn~nKd zMwQF)l}X+h?OU3_0@*>2fP;6pJGyq$9Ph1|mtvHTOva3%^LyjsBRG_yG}c=|l>1l@ zbaoiA>(hNDpOh0h3-}e*K=R{YzwT0wYR3~}@PJGkH( z#Gy*jHKs!^4~9&Nwg=u0;%)nGWS*6k@iLHi`X6Iw5QzU&%w%<+&8Fdp6kP*3IZ)l5 z(d;r@@$DQ80xLKKfeqy&U7I?n-jqUK|LkS=u8eBIy?uz6n1Kj*vVLP8D}!7sSc$Ga zmX2+%vA#I-XE~{et-sz0-sPRTstHB95L>VR(J1>DC?3K9RwJrn+RcwNhy;qALwnJ* zWh%G69a3x&Qxz5MWqrQproY25d3#vg3V6+NCTqSDZX>#bVZBE8V?;%t%*yGYq=^|t zapb~V((4@0H^4Eie;0oOezU#iNlK%=C2UjDJ*dB_zCEed3Qcmc^sbXD-*X+YpaoqK z4?bvdU7vk!br!tV6mzabHr#<;mMA-SQ2K-LK6kcMG(GJH^}O^OnFvDC@99OJ1h=xo zn(Jz0xh}iIqu)cZ8~xLf2Ei?PcsYQ;9ppFYTJ4TUKBH_S+1YuE*`vXyGFUWgTNtsA z@M zdfzMV#HdlP%jy?K@bPykNz&96lDwZkmQr}CbvnU6nXP40rd+~Z{KK9bLcQZpA{wFUqe!3J{G2&0%-r5qPzkjzPHJ?*oAEUP@i;8ki~*X_!Z%&~@Z<8FF_+`&VExY2Ep) zK{FaePh*88fnE_oHMxwdeVAR$WKuH>X{g>}!cW!u^2~34G`WJY_Nf(6FM*NkhJM`D zWxMQPq@E1`-o~&=EEIhelTod|uVLoqDgzr+nvb)u<%7f>dwLDm@jX^mH978SQ_)?I zH4?yDM*dUaj>pN0$BtkSu+D6Rdh71VdZ+#fs*Su$m%xBhsyNJZR+bcS)%!<}l02 z@NB!hs0-i7^K!#Nm|C~R*hSj&fyPS~%L__|<#(xRw(TRfAd>?Vso;i30*H$A^uX9J zUz7OW%~kT4-=Mb~U}SiUd*6il-fmb71w)8yUpQ7?FQ}&Qf>{LK#~xj^&@sYG2M8$dpvI~Zsh#po2R&kN4H$viL=pAW3s{6%8hC7b(nqhFR+q9+W>-Lc4_Z*0`WwYpr#Abe=pXcVzr@H{DrXp1pCU>51*@dPUe_ zt@`?C1BvZMaSD$P%0 z^f`N7W3({14iW)g?+tr=smb~bTA2M9RLy8+X0L*+8bwiS9N8hyYxf5CNSz;TJ`LfZ z_)KW7FMrQ+V01-knWc5XgrG+%RgUP){El-=$r|}nJ2}|FK3q0Geg4Zxkqn!?)$u+t z;5H4qnjZ)s_n>)E!9wcsRn~6(@8ZNcW#DDQy>0%}=T5CUZn%66znuYFY(~~_M+4I+ zbaptLc-ky4FKDO9JFC$oVo(yK0l&O9%r!xh|C0JIcY-0X&&`kCqJ4WGbN2ypmvH#m zE!f5|m{V_1U{8H&BY;XybN=8L)M`gK?Uv}5lu7J5lHE#eAM!pT_D(ge6Ph!3jJcJ% ztg%AzXm}{FO+c2hR-Li5RhBvltJAM^kKmF7L{oMoMHXWs7BhrTV5XOyfMD9`NvdOo zyGw^GUW0nTm2l#3H-sby;`8;#%+5wt`%->uDk6Tdw~rpPhKNYC`6>6{MuM;|)2<&#`Z!e3Yr!N2R5AVG!;W}YW)QN}Ez4JF&flogBM8?Zh#PJONq=1G= zYfAfV_wyO9^JtZw439Lb1(aD~ZDl+!FMkIth6;<>S1#avXsTX+4_#vfniOTk#&v31 zXcu*aP1(E0&Avorh4)7Se`4su#4x>AjWCkSfWMXTk4I{aV9l}qyuJ5>{ioR$zCC*o zQmHlWe8v=!s23WZrL(R5+E6nSVivKaoVU^f!xkcYD$1B8k@{6a@m2z)k&l_*j#8dp zJm-~V=ygxB%(}La{AiC>F0E^(X{ZqXj7^o#IwR;U^H)tEUJJ_$*bory7 znqOuVxpyEk$iS`%?E*pnWoo`|0-u!iIxGn~QT4iT1GzqsdY3MLHjoZVEtytb_psQTnf6Kq-ZMXDG8G?=ha~5xd_kUMjQH;rOyZTTIEZiF zcWPUax5u}=pTBr*9q;@RAv?Nv=@Puojq}NwM(Oz&DjXeY{wwW1EXQ^w1329tL-H+s9UB%W2e{TNN zIFx$67`jMG-de{$tsvZ&z0F1B6#Fu&FVj;#ddUGIL0*gn%-wC#$-E;1fvW07^A|OQ z*xY4eX4Bu(GI3B4m1q#d)*RK!L;FQys}nvIqm`TbG*&Lf?UUGo2^&Ufsr*eTKJ7jx z-VJ}BnqCCLA1Wd_b7NB1V)BI(*U;OjrbJYz4S`g@ne3;* z<_4q3ApZj_djGIy8s+&TL#feJ{G{sP2C8m$mUwp*dA{7^t_yf8qT+!~SYHUB8eTr7 zGY->mO8^}C(f!~3%GVQ@dFY7qiH$W8YdoHh7bzG;DkT0T?#0$j$osHtA9$N2pZ_2K z1lUjFG>;wicY(~>$;)OUvl|1mCY@pRXy&PpXhLa-n?fg?kvEJ2rg zb{ZS+uXHX^kZ3OiwKnq9^IY}qyr%Z(X6!pjV+ut*Hk8Vmkecx-VQSOmNEY(q=)WcQ zs@SuC@^*LztQCJvd>ezQFEYTEg-o}v>OZ(PlLNj?yXh0AbBx$bOQ z$YTml7{K#?06_1%K!M^X{kj251DzN)C#HXIO#Mb@Us5YSv`+7V~`Uy9es8#Ux;(Qzf<8THuZRdC@CIXSeXV z6s6B(W?uril&aF#ysM7y(V38qK!z(dNJ63LqvPIiya%Z3;kh^w7N#8P>fvZPH}MLZ zvrV@*7ydS8LBIuGu(=%L<(cUWlJ{6dni>mNO2|%ww#x{p2QZXXI-fFVSlZkNXMB@m|PzPE`-pXb=Q+G~f zj+*&6qqNd1ZV#V>t2gtw_5dI$LkE0BGqpK^44+vZ6x%x7>pTB%-(Kw%+Bcn!0_x7c zm>lj*19QH-!$X-P%9zC=UeTPJw%eAgWev-vMVqLI{o${e7_PYjsU-St_OUrhC<%1M(*9c zLO~l%6SA#woWJy&xayd;P;+Qfi4{Bg@r*K{V^$Z5uaDyEnca^BUP6>Zi0oA#&!^iT z*w%@{Bo7OFjH-&ic@i29H6}{#V2fBWeWVoiz@TVcVc;EoO1=46?vHtUzzWMe{Cw)w;(NN8td?uzx~aK_YWd(NjpRvwrW*0Y zKf8jj=htFShuZ9s z>RJv>>}Og1T^>z#HoGULoQ@`EtQquIB^mRal($|W2oe4AsI+_*f^6ip$Cw!l$dNqA ze?2kk?Px^Z-E&;o-Et5q%lZn^FAcxK_=2a>cj<(QYVLbn;A!Hx7Kni3F$f5FX1Fh+ z6b~=?<++9`b`=0Q9-(OHXm%LpJ~^`+iXm8E^Y+V$z0Lg=U_rEBe*wUWmad`Yfhn-K3E@*&Kw*oV|;zdTM!{Iuw=n#1tQ! z9nG?@1D`kofhxhGU2A5>H;vhVO&w}N6g8SZ1Zae<1-%DbKw{zZoQ9+4iymWrcMlIp z>*>kG`x!NlD%DW0MDO>8K;JDe96bZRy`A4=z)h-^U%t+d?-eY%UdUF2xTw+w_bYR5 zY^|1Vx{sv<`UvE{{;09Ny$whdliMxSDd~%gxDLODlvRe&C>%Sx=eysalp&jrCaSka zt}}12Y=w-U7D{q(^8&i&iMlmvWfSDE zxRXB7+Swh=F;GSE<60lcgqPW0w5>O*Lnw@a&g9EtKfNd>4r9rQqm0rtu>Fb!+w9|v z!^nc{XZn1ehel!Yet#arsokuGx-d5zEe}x$onbclINg7~$5J6QC~u=g0sY!?0{UXL zYFiItSCVJBd`Uv~>&)~E1*5+G`$Zq#l1LU>9@XWOBa)LwjHAI2+x*=Qa?fw)cUx$& z&90|RDI?TrXEiSB`>@{o@7?>j`%e}wV*B3Z>&uKkmPK>=lRt+>qZt|B`KD(tV5t6Lc7oTq z-|8_@#)p`Mq={1eNrP2>Gg63iCm2B>UI`h~$~XsFg=C1n?JC;6>-?7t7?VQY zk(XLk7jaVyD%8^ z8tVT04b<%`)g_PVIorRK5x42OOt}6u{6RS88Yj5qukENeNsFOeDE??VKQhSw z1C!Llx6eg+7zPHLS8zQ;uz>}(u;@-5%+%f_G*dl7Ct_dm-rw6A?(pbBgTKc|0)-rn zS?U>6cAd!M-=n0a?y3n~3Ja~-58YTSEp1VBw(8gj^-5)KHLSAIDn!}A<}mdFcId>j zSR1JkzjQBVNNu0>ZjJj<0G|H*qW?@p@lZl@-*DLiUU6K{G#o)3C%vT0f9F)^xEdg4 z&|%5Dwtj{@m(ZA9xAATLdp-#Z{(Fz(ZIc>w$}EY02ZiQ(Ea8F8!W0_mT!Mh+-2S-OCvZWPtfTNf-z3*wqrQ3+C1)W}@;2m24?c*3Yvcf;3Wx5ywKv^SaB zrzO4RrRVy-;-uI;;Y!Zlx}odY#F7;=Q8KK8{fNos-KCuHwQUp7oz*b`7JVCz?@ZA; zXYwwM9qAzLhlXgi1g;g7oK4w}*_X!?^&Hf}I=JVkgziUqIT!hF;I|11zbp9l7RP+( zCeVKb`3ihAQvjm>3pBVtDS;mXHh5K&j4WceRtiD78yXN(fBaZQ6@R3Ltc*~!5GqAI z!p=p9K=5*)ng3(;4be=`+hhRRwV;7UE@a0mn^#afF63QQ(0^GQN=S!6kIH}O!{TBq zS|hfHB)B3&?1jFumi+$S$K8+LJ%L@yb0wXCU?X%fSxqh2x1M9l8;agq{Tqd}zI;G5 z*#tvok17sjUEf@Cjq177)(o)1E)sc682-nNxkrTp2@N;j&?sd&e`oDYF&&$d!F|L( zfN4R^?yxJrEt8A+ntSt^vAuNsCnw_qB@MaMrt7&TU_xq?^g(DezaM}eCO3kH@ZIkO zeyU;FAXA*Fg^OLD^qCME?~Gk4w!onDi+n*;| zn^F5G+J4__uIv7{jEVM=(dJYu{21AI{)s(j`eT0>dXMB^&YNH9+-J^}DIUByJ(SVA zo^MoPpjF(SF3E*4*B2F+NteFZdiyrlROl86s^Pobv4tik<9j`HbpAvHXc%zpxxmwZ zkKOmR_M>EOZ?KX^STDCo7K&Sow`g#84-SPu za4jVvXmGf^_q)G)zd!ExwlkSbX3m~-PWIY+t!K%8Rwq95^3H>fVzY9)|7ec?kAnF> zm(nsiiK#pGi1W`!trJ462!{xAa-Z=ZzBS~Fi&LR|kIbj~nbtp93UjZeXdLL*c~ z(n^V&CX|Lh^?9-O?mDHil8wq&W?C%K99oXraPAZpDPg{I?93jDKsFO(4rBL|;kB;T z5xtsls@~A?Bq7?&f{k*-@%gAQa__Y~m?u1WnAa$j^oDz8wC$xx%O^0$~oJcmk)AtGyE2r<`h$*Zr^-zU;5m{Q#$}9fn zz{+17stI0tqD(HkoZtG!j*BmzN!E^NWZ+0J01KgHth<3`*_-{Sse3s&%iAe8e*`oVFZBC1gLySJF3V;?AbuK;F;f(K!tzO9I zHk`)E%&hbEL%M4cYv$pBWab}od?xdo35KQJm3X5c*}`*jvs48C&7b_Qm|xWd{s{V^ z)Ufy$M~-cCd#7R&1+oxr4^p#&(5a1_70S3z!5MjkR>J#&ua#e^?+2?Mrk`mk5_Gd- zn=+cqIm~v+6}_6e;EakreV1SM75cQ>-~f-9)v)%<&WwWA3U>ROoR~rr%_?C$i!y;G zO)jF{HxG`QqavQvwN7%?C(Kbk&?=sz$Q4u~OWe3!i1P~jVuZ?474~TQO{TAT!eKMN zOv=Z1X{?qaSrgZKN}8p_NU(fOD0(DuF(A@fe7I&7xY-@h+>vGzfu6+kD3tK@KCk~RbD1Ih|1k@{xkAhIzJy(Ai_7Ex7e@-TJ9dd#$QJ8K_6TCag0D;>pp}fu)cY5aA|{XMu@&>?e(PP z?$!y#-EoBP6TIRA0iS%Z)hn*6tH1EE{e8}`;YD=n2F~#z`QAUk?r$+Vcu>L+qH=Lx z`ed&ueTdcCrg^@J8<-0fiN4MfSnnDzY0Ua9Y)lAB;oa(5-3nI?i2joXj_Oob4%)jL z1Cu?aj}mVs`eBkCr$9%bXwU0qoJhO;hAsN(L9<|^8vL`uFLz(+b?r|kH^DUIkf;k5 zb(Z$PUATUr^gyjN`^6zgbjLTG{sG%v$={H#W{(h-w;3E_64`Vq6_O_Tv4+1rjelY_ z%4fX)Frz&{`3>&5Y-6uTSK8-O{%kGnP@%H0HI>@Yz*+kJGn3nQwVXLh_^qW0O|gle z1=U^L$2^C2_xiv1&-ySAf5xHCX(4g@q|np&it%mRw(mH-bn%wZy#*Mz)4t}cKJq9$9)dtQ~l&B_H1HCIv!eK|TrVss>{#`>{sbKZv8zc_lX@DH}_ zALAz<-AR9NUG$7{yTl#4u#|0Dz0m*X)YNo(v>^7%ckP;pZ59GO1%IdQ3*#E@FN}LH zH!I#aYJX@Zd7Z4qvE9BV*xTr1DkZGWYiy_EAH8715e>f1IA=H>-!!r$*PioZS)8ut zcrgbXZV^dnCC=-0VVMA{Ln4(p@*iD;nMAfrd zGG}41m|UePN%;@?WXU*DR(@t)oQ}3Zjm=1&SWh4JpiI=8gv;e#?cBt^Q28vbbl6~* zycqRt>6lKk2KjL;Fd_7J^$)9XH+tMP$y`!MPR-JoC}(AN;WY#sV(H?n+ZP(pEuY|c z7jSrsccCbExpA=Ov~FF-|J;KR&Ch#I`Vg!g!hbbhcnf}pMsgbwPDQ5}z_N3ayK4vy z9ijD5xhm#Y&{Y1HtowgmGFu~0dz`bP)s7$JOGAy>UMt|OoS|RGl&?nFTh8qJEal;J zn3|T^59-NHRzqW|Z|t1bap}MJ?EHTN!RtjBHUYoiXP-_AH^w01d1K3?3@%y)`J`hc zEQb599_GrLwrBG^`{IA$JN-=4duhEw0(JZ_KU!oPs_0S zgL^>No4Sms$-2a;**S|P%vufcQhu-BQdJ)ryL8wyw(;RC%l4QQB7A#`pT2R%M2P75 z)1?>98@rk7rF|x1<={${b~a;nVX{?E6Pa&mwXwJSP~30EJE;y-#*tqCjo0|%tU9vE zMJ5#46^AU2**F9dkRJSyAGLj{x0DO>IDAYiEU5WlybT`uDPEGruV+c>ZJN_5C65?y zFZ;abgZ~*R{NF@tBL;?;{B_aG=ik0-jad4#GCw7@Pl-+lQA>W3p;Vk<9OtwVfY_xM zx*$;dj?CxgkTuPbD|d&D!}uBu&aXm6=;`Fwl+ z96bxM7PzE8Z^mXkzA3CeP)qP<$unb!Wpxri=-A2oAvN9pmBU!4Pdk<4Yx;rAw0rXY z<%5#bwbOFFI^z!*YiC8xo)=Gv8pB-9p1RM;p{hk@et-L=@jsWa{AZt4kO$K}2{g^0 zH7d0*Uen;#Z|yf}JKrSltv>O1^dS5oE&A**W1Q-~6vi1VxN!jWrQ35u@8W%I)@XG_ zKgkx=AH^G-85GougzRrJ`)hWvxl^_q_^2^)ugfUAVv~~v@2R6nxo+&G`rjF)p%V6- zB7Xl{K=D5hYsA5t;zB&*xRs<#Z(3fb+G|;qyid8dlNh}Xzt_MF=%y%Xf)y{#?aooJ zJBCb5rxg4@&$a*rYrErIoq6t^c*fAwR$R`~Rsqb%**`^kYM1Rv&=A=WG<>FfGV= zImJ}{L%->lbB70<{l`DQl(+uH-A(cB=8qx!O&N<{P#a_C?W{L(rjew#h(F7%K>u&hx)kob$5G6BIUR>kv!GJf;+ z#X^7|aR*^tI>#|K5gaQ)B*)jPN$oF|TGI=&<(L%@9kJ#Jj1?m~g=$+}JiA^p%L1}- za$Y3=p}O~4i=gR9WzApM@y=2Ce{LqG#Qr_*6w3&we4oMi&T)Cgcn8>IBu$fYSMh}< z0QXRmIZ6@e-X4ZhUu$)%JolBOoH8RjxA+p{JHMZw17iMDrtqgWDM_ia{CqPC3TudMbxK`z^0yDEkOMsL zLn&){9g>r4zKtPA{h3+}l|5o-lU5Eu`KUDI_-V{HDxf{x>$0)Pgwnwa8ehx0N!Woee$d) z-_MVFCpR8cWE{16>RzTPW2pBcOOp(3C+jav-o87Jf6nQ+!7;FccKiHbwR%(fpsZV@ zQEB-T_ja7EbbD;4HV$s2qpRHn4$g}*0UJ@l2>r9`Z5^ol$HMWY2Y1HJLUepRMo<5| zQqjrN^06|aR%%6}mbz@Bj3$zV$eMk81}VQOPws)bdGx{ru#>rBFb^q*D4&~&;?KmD zh>K+6t=AarjJ~7pSQV!i33K9+a>jnp*|ZparL5b{6aK~rGtic)hsf+Xue zY}`3g^CU;iWXM_!GEH?i&OMvSa0fi?Pt^Ww7@nJbdyuAh4WuG+DoUfoDkMOy78cun zmyR#N7ym$AUT8Vvr&nvBr&n4BtTVt?6lW0G{Z4CL;$u>R_OpUc9t~oyllw01DaP&7 z!l1Y}!BuhmhtN0k5x4_RUtI=YZ&3C$tt&AeiF7QjodwUY^M~)W{UA-DCZ!JBgK$Z| z^2aAVEEUp9|1%zx$J!S8N7l*(C6YfW`-OUu?zH<~=d~c4Y>q=evdTML!ks{_7;Mhz}Eb($y%tNWYd!JR6sv=DO`hA2w*TLFYY$#7_ z3&dFWkwe3Dz*DKlh80w+=dgyeoC}Qxb(uCiLLfdj)@uHk`CZKuwb;WBZg7}y-Y4zKVG5iuIq!15n$$C?sTmk356LFs;tQO{l|H2I&{mRW z;*Cmj%zL&g%+ppN=B>tmc=e-M@h^m6mP2936&P6v`R3abBNckn>idN&^x&MazR*Dm zQFC{NS-)i*aryi&-dG;1B1c~5P>NDjE7n4v_K3Pw(Zh1Kt*lQLbx{t41vrT=9EsjL z+fQ=x)l^9jS*wKt@TfLVg%Uy8_Zt$g@f?A1Uii9&URgALK{dGvEr%VFqSq-9y-Eqr zrf%;^=23Riu%oS2B-HgEOn?^Q?pGz;&EBB0pV$HjcYgFwInsjb*_%3tZr7pVA4l8paTZdw`wy*@bF`4Ogo|6{{3@<~o z=CSJ_pP3CxL-5p8m_yyXc009H$i0hL#HPcJ<&4jx^BAmpL&**9HfW`OY~;YXbO+<1 zZ_Ec%JiVZgnM^G!+h%O80wt}&&9^rgSJhPUZ{A}-wEr(^|F<8(rH?1xDsK`DYK`Qb z0VM#nV>zNNcQOrzfs1bO&1 zPG#{?Gf~2}J6kHfAj8H{+F;iOquZEDtBpVP_(oSPi|J{MfF&V~V)sN~#loBZ6r3g$ zKDX7FAWY5Fml_+>DU67aXs8`8J!7ArJ z{lbc(rwj3d(AX_~qAu;CU#C@}cWhZ1AkRzSARS9_J@%;Qx0n{AJ#mdOr80U zdXqh%d-_c@2xAWLX&)DvP?F6y^vIdz(|uvYYI$Z!@Pi-W1=GB>dm?oc^_@?bV$N-p zh$`PkpD(96?oOFNb}nkjdtLay#amm6G{MiG+x`WxK__pd#^PfM%pd;Joa|N!;4(g4 z&M{(bHo=I0pC;E?<1_9_C}{Nhmuk#MvFe-D>SOJC<7S4kHN!I?StmQ}QOaJW`rx4A z1WHcQ=PE5*o{hwpZ-+Q{^R*r6EJsyVW%}4D(ZdOhMN4Ou!SNSMy)3DHfvahrokM&E zM&ow%_Z<2|T}!=|FVt!NILE)Qumx)R80+sPa`unaf z>5uQ?5iw3#Kc1bWYlv$kZ)OaP_l~L33eqgNanki1Pdt`beAC!h5>A$Ldebh$#u*0j zyHb+gU_2d6E+Fnc8~JTm@|^=1iIf5ia$=l6H!_2W-}_a6e6xE1B88O^vr^%#RaO`& zHZ~*+p)HA`h394klkKmYP0J)qhs-b9m+%ElurA<#zW3(un4xJh^vv^-E&bDy8+N?Y5zGH^l+EJ z!+#vfKYz?f9@y~(wtS<+*Xhly|}YmpwjjzuC;FT zc$_)c#ZMacptr_D^3aOf&de6baG@@QQnIXk(YjEvPa{`y$GXC#rN5dtKV>L^d5IZy z&4_C2-MvF}dvla+Z^0pXJ&8}+CyT;Cq>NcuL62Q?qi?&PeoeVY%YV#gjgVsKM6Y~Y z%&x^)rxB@q?KO_HN!+})J4iNo)x{qj_=I8;ZfF$nyg)w71$$>xs?HT3#U^}ml5N9UZaXEkcSFDDJIFff!yGuqDboM znOs5V@(h)Oa=!+I666Fo8Uwb?*y65;+x4)I_P^*4U{nM_IQQn?Ry!dLExg-23hQ{C zL(yby`i8M)r8vGuu3cnv$*GxqeR^nDi|Q9>39Os-Tf6-EJ>$<}xfh+;HdaRTiq>|X z*6h^PDP(#~<~}1wSRZzD@nkttxntV?B5c>rL5+Z%z8Il`c*t;C0(kvX3v^mRi2AHqS$~?D zYTy8?Qn!kDL!T;RTYgLad#(I0tnxprqciJ?z^iMLZr-PI(FKPupQ{iA?|+XyfB1|& z^I7H#@Ha4+QZfHcoH&gkOHoQQ^A|Ot{n-3hC6w1*H!Z!07%+1gGL$mpneKnu9aB{n zBmzI2*h>k1nd4NaEof`7Ii%)k=vMZV?KS3XOTlRL7K_g-(hJ6gr_sG+NygPLmL?4( z^=Su4od_*_s~+TP$ybK4{3`M*ttxKKRU-P>TRLG^%L9=dVvgES%Pkyrv<3ID;eZ_P zP=cV}bdiYjWpr-SAcjH>D|zFIeO}yg*N2Amc3>Tve)!1Hv8ZQ-S?=YvO#N+z38Y5V zc#~au-;Jr7)=n+*+mA|O6QS_LWKp~OFxYgZr+Nel0ql)P6;O{YQ z@e-qHr*n#*LU+C5#J{L?Al^so2d)z{6!?94w_8hS`?~%n-CWAsd2#>4I03BDiQF(G zpwgZI%heBP>#D=4gu}nXD>i9qn~(~>D2|8un38A?l(iN2&AMb(c`tTg&5;e%n5Vm* z6}?#E8G^y{OWsrE?aDCb;0C_^#+iO>*8D3uUWiAs@%Y_D z^d91DiglQ4)cqu)_rVN+&>4Wx)%zPjb3aBb?H}wL_4(~{&I~qOqQaSn&pW=9_=eKC zTK*t~gy}4f=}I~tyq&MVJ1HwSOs|nbBJ1GQBzVOX0{0A43K{*j>8kEMduhYmWH#Uq zPwaI;mykCk%_li*)-;Kn)GA$Rw$c%Usu!(T<|((c(lj;74#8&G$78{RM5H@BN4Vp^ zp1u?AD9g2Z&#n3JR&6$bo&-{tCTsfLr^CCu}iNQ(t zF~qy3oN;44HnLTAmHxuU-7C{ooPRv*BISw*wjDF`wiB9l=XlL}X~xe)Sb9-a26zj+ z6W+%&uT(rzLU+JaEUpc2ei1hbC5z%si?2Q%dmOc*%x(Mi3G9< z66Su8p0}-eoVuCsu?1g(`|5l)9ieJ{>YF+J%xoF`>ZNfMU_4Lss<&9qYOB7it?ue; z+wBnmb-iL-D}@|`3i0IT6tX{aER}Dq=LvLCV@|J~;%%|k36~!Dm;^ODI$8)OU&dRInN|}3i z%%oDQiqXdA(M86TPFY|4;`z7gzW=vpTto5I9tWBZ3lRi~h2lL_MxIFcS?Qz|eI-J# zdycfsT6>k%ce`@JM(JRlmi+T}BA9GnMw9B!Txa zF1#rebKI?c3ZaJe-6k?D%9({vCOR!wJu>h^oa&M4>w!w^8tPyl+tF)g6M0wOR+a0A zWTi~NKqvlVB>TS`Jc{4k`OG#`r#enA#W-zo!L5zM<~-0v6;0);ugc9HbwUfcCah} zUT^6_3j3Uoc@Pr$khIQscOiNS{2i9Ui##xQN7c>;2Vl0JNHTPTW>cItwn+eW@0;S{ zi5DCW_&R**?YzqXP6MP_)rVj=K<)ePeP5rZI{pZ>9Hvltb%pGW#Byb`)Yaw?pq>D} zxu>{`t>zaeGB1UpNZI)2NjWNlT~Q0(#S!l?ETJ4P&D=`h^$-5zB+ z@uZq}*qh@XE(cb=K(1dV=JdxV690ZC_rKxFZH(YjvW}gQi@BbN=O>U)(DeZ@k(l(4+;gVLvYN*(h;p)y z&+L(0b55b1#Nf*c(0*+U4K92h$<$!XpLNjItXfj+kUl?q^#buYS3l;ai3Md5j>Ip+ zYu~uYN4-8QiA#B1f1Z*hbG~Mc8f4cqRB?&f5+Vx#9M8^UYC6vdib$Hvfe;1&5MA$Y zFJsiCDa>pM0&qI47KQZeT~6engVsLk)FVe@^tl+8e+||+8Z%x+^EX7wRXrN1My+dV zEbQ@Tfp3Km^dkcoTcmAwmfN~zFTelP?Jfwm{ZKV`iL!N^UO<1m0%N zgFZCPHK#Nfd>3*y_&WZTUmP6N4J50;-02F=%a)2eg@Uu1+vFSn~87 zPy1W9R1x*JV|}8sGZw}1@@2&yVlX1j!=sl&IO9~zw+%`>wt*?(&Hf*~fPs`9213Zc za}VxAei-NG(Y^^%>(?-XF1@+^HgKayXr$Ps?~i&*ORXr zhV1BxrV&D2#(>}#9deFmi*?IfkF#}U6AA~`!i*RP+E?`-wM9K`B&7Lt$BG4=H2G39 z*w2h*OKt6Vx~*JqzJVj|WKF7c6i;)B82JAJ~?LbhgH<@LHyp~s_ zjCFIlQciR(a<&alMr*7$;=1(31E< zXPjGXzca|XFSlQ;m{i39QlQN+z4-_b$gwX`nQRE)=viepE(3-DZ#^e;c}(A*wR(rE zQ}(ZI1uOvDp|%an3)aTQ2%zVRufxF9PJ(Rp@{5>!;A&ih(|{%)w5a?B2t#lSa-ymC z_67;xGoa_g;Oi5O2%n3uHz!g9@Ct9Bp`PZLApkGETkH(I_)LtQr4y1f_hu%hFELJ2 ze(7xN>+5)vACzVJr4~qkB=w%Yq($kzU6;@)0(GE*1b-9uy_)=n`QZFZY8ur4+ZN>(g$8k zFUIe78IdqY2Y- zoh=6dk7mv;>?ZB7L@?EXgG26#F_%Rbfq+k7L9Ny0vkLHsYe0fNlk^}dy)=#sDo>qA z0p2gPc|olq8Wbw357J}~XjJ4$VISXCO>yXYcKZHoh7ADUGG=Tz-nlBryvj9wC}r)6 z)o@HR_ASuIPwAJfps;J1iySatY<<@?k>JIPV<%&z!{nTq<9 zJ+8o|29~kh0TCXNo7Q=mjcrS_jrsbj)Q0@dwksCPkH-(B+l2LznOD}9U9LRd8l;<| zS+Ld5iw-jSf&p{OZS{9sOt3+Y6h$WbzN5v7ngKAWn6h!yuWN_}^0z;>sxyGDwblc= z^N4YjtRJl3Ft-FQ`RP1Qr0I&+yeC=~^fJzRB+^XX_alRp_&TIq?tD-Ns!Cs2mjG2F z%V*+j=uvHfU1|_D%C9s-%Ro=Dj&nkIO_vDx51s;1n*xpsGV{9U@01)Psz#0zlVjl1 z9fwg2ivc4f`%>lsk*j^TM{ZI9&XrDvXI0q}1f-{e1%T=Idt&8P^%Z$rEgq;~)A{x6 z#f$;%&EgjmMb1(mPQq@?u7pK>%olMqlFMquY#%>9*(f>_6>$)NDr%n3Dgf#URI7UW z(c!8l862HCDFRJs_?V{xV~xGipaP6E#1d51-=6NdW9PQX5*43LE_f~2ji>ZhGDRlx z?0g--LyA0L3b1WSj$A_;8?4*EK|hkmi#+xoKhkj6>%|Hpy2M*=0(}BG=jzc6{f5kJnyK_R#xatSD933-&;Iw4Asb`70`W_g*ExT}3%P1_I5{AU=AIug(bQBGr?5 z!YuH%ldrMj&3z;ix-{?(_7Sl@KII1uG9~BB=`SdD>Kf|?r2zQvNw|9eOoPq1* z1k&FI%7dO8_{i)qVU|b7O7GUYk>vhECsQ{-)fJGB8A~H!EE;CDz~UN733p|J+UqL`#fnrC)I=BIWF|tb)g)Q zH3&@-=;t=fl)ImzfadqzIF~HXdmwF8rB%}{mnfL-LZWp!@K-qt++jJAs+VOo^#y!> zr>g7+NV5m5E7MXvqDa|J{;Z}U9vmqvI=^)XXps2e~P;N7+6Z#g`0Cm>$6VB#-e6K56+cC zAAHL7dzFCy%AM9Un1_wrYJ!%m6B%e%ep>b-z)Ve0dL~q-B#eeYV|9UW1%vmm3~Q>= z>Z6Y{`IAoX9pHz~ke7a%n1b0g$@zxk1Cyci$MbF5FT^v{Z+7Q|Il5 zzRt^6g)2V$3kXhKUPva8POl;JHXt45*cyjk1=^QpGf3L2)RRJK&g5*J%0Ib)9erF} zicf7)4OB@S{8|v_1z$(J=GIQ(kbs_Bg0uGi{&fR?KERYSQvlp#4`dmcE#)(LyH1)@ zYwhg`n->n9jgV|;_ohW*@k3d8j02JRG2qy%duW67?u0O~3a1LG7&I&{nJ@7|%4$o{ zicex0WZY-kFAy%!-F9JMUgh|L->UWU@Fgb@*TlM>clzTsMSFu-UqJMlvd_mINL4CP z>*PphWGg$38bPP_G51_qmACAoQ)ENO`cInQeRIMz>JrA(*1ypcQoiy=tiosZNE;UC1%kG6kL~?|}%%rt|~-e-3K^&VuHP zKip_Jm`ZM{hJM)8K~@>5bk%owF5_Hr&Hl8kcMP2e$yN{TH=XH9`JFeOo_fzu%JcwB zTsrE2*6?^0sWp}a6mPiv(n3OEKdhYYDkDjSGdJ?Uf7s8ZPj;oMu8wYb*Jzy~XIr6V zhjDkNjZ;JTNdP+Rm|>&-^fnn4tmz15?`Rp17$X7rmSMX~NVfr6jGph9tWv?#HNZ^K zlBf&Dx}10AsKb@U9_RUP8R(jUX65CRsuXCApvK?js_uiC%FIa!eI}~s4I|3Rsh7-W zU752&(6fgirOM!{%MZ760R_A@`FasVv<8Sg&h51VqVoO!4f|>CK59d5EJ(5~w~j~55DO*xu{B79=DuP#q+J@xy6=81?H=@+Lsb5g6xf(}!;^EE_DvuKr#Pp-F_hB<&; z_0I5)CG&iJoB*=rrECUv_&K7fe$S8hr_nc`KYK8YMa)gb zykN8kDw@JqXl4+N4T44?r8E+pLUDlyI0Lt<_g|jqRp!#E zsskT+zn)3%YjNoFRFAFmiUMsu%bfM}pr(=g4Qn10y7cndYN1r)~*?V(ox z6EY3gReIdA+VOdk^EZE!fg=mv#wt3v)_BgAQ{s3r*&39|E*c%;C|I%kOl^%M&xCy4 z`14*)iz{9ii5_J#i{M5ydRmRRyS@fpw+DH*TX;8^Fog1~YC=3^wMbuGLCPvr;8zmq z>nKYD7D|?f-7d7a&vzV2^2AcFw)bZ!Ygn8%I5s&(j^(r4b4AyiJjJmNm;-gt$5wNm zDqN3|_%YB%4bBsVA7)X32Y}dD$pGuY*X3kL!0_x8PUQi$(Ut7dpsM+U6su2>7w!gG zpj|Ktpo$Wdes9Kf4ZDif1Z%Jpxx!pOL|h6eFavCwSqg9;){_9g)TDW?CE*T!D%XrD z4t7JMqSYy}&NiTfBcdgcbd_d6K!G2GLx5aOAdKiYocWUQi5?ygwXvZI7u1UmH9}Vht zo6^ov`N20bf&<&X0T;UK<@HrwoZCivHf~eQ4yljUWPkbrp}gK5-S21S-8w0Y8FMt| zmTu-I8*91)rZIO)c7Il&wU*{yHNZDnv5va(<=Kg6W%fuSgj?I!rV=0cFSD{Ktg<5_ zWg4wWeO8|#+%ys7YIta`)LssH8P}?l^43W)`QtI}V#B--1X5(idoTkQC1C)k<5@s? ztS42}W#1w;-KZJ9pU=Q_Aj+jg`0W~1(c{D)8`I$d+dlTQt2S?QHf5- z0f!MnnaKG|`|I|DWlE!-sf8#diP&<2_Ft*1zUrJA76Qn0?9+_|R`*d;dWnDsm^s2v zAif~K*=YYVIxb1Z>cH9VK+VO=yPlMTrd$Y-t%`@SiS`CnO}Gg&in2! z5xcd#obxP8B3W_$66ZK*ibG+Tra-TJF7Pqvfq3q5=(^9tNdFfxgVDgIbQW?7Kjszr z;-IXTaZi_O5YV~Bh%%wz!sXO0r{gKzs1*r^uH}_v))cF8hRDb(fg*a!r2%Qo!)(=s zX^$oK15q}r#aeca3g$R*Mps@wF@)Wlo`%G~md3x-yqG^%xb$ zXW@oOc`#-h*x-pKDRzhXyfV_0aeB5Tu}r zqSD6YXI@nEwAE8|rRDL35{?A+k#<}Aeu`*g1QLar%DPJ((2G&#aDIvWVy@~C-SF+X zpGRb(-7B)V^hijKPP2ylT5sW;dG>(31Q1=kHd!_4u>j{@cRGeoB8A(R1q14hgMoT? zO&1=Qv8@SV{SX=C&kG$qsKVfwrM;KozNkXu*jJ|$%QJaKJEcKthwk~io=EOrEcS?` z-EP;h>Nj5uLQY2UaSfPB%OBRb%f={=l8ZM4-EODhb!JJ#o-%g|GX`6S-F4rLUVm)o zw5Ub{mFaKJggktyq3~D9m2I5hSL@y)+&+OVx47V#oGJr{ac?u^j@wxdZ*o=HsXEn^ zqUrC2aQ)XES`Rko3%4m5{J7Z@g`XoIHcB@WR!|xkXw>PO%#a)<X+a!xBInk2_%n({5te%p zBN?EH_gNcjy?1@IcIVfrac!)wx%}tG!@K04eoM~?yc&F;MYky z=#3tU<^N3M^XV+MEan&H31z(cx_tEN^j-L&=Y_eNCJjaJ^<}lgF8fbyP%T;|m#hw& zYBww`PScFmm(OxsoGH>ukg6CPPf7i64uYiBU=>kyaQ2tQ*-hkI__xedp`k&XC84E?!@N9wT)R`!cA8|k{#+pN;6|Oh2K}&h>?R`Ayj^;{o zh0b zCv4@QL~mM{{M){sy$MMgC$L!1oH196>)w>q`g+Zt*$ZQ;88v>d8S6#`F|AFYMpdvw zj(7{5)wtt3i0DjQFoZ)ql@L&P-l4kSu`V>o`ThSNn!7MUGXIAQ;D47ejJ`H|eVDml zN!4z*#rSipHI76LN+&00&znq@!hNa_cEv9~%uFs>;Kd*eLo1N!TurJF13*gHi5-Yy%uf9GbiX{A;T3W(t$`&)kEY3&O`m0w-EQ#1_ zeHw9365E!?J1001&*NmiXRqz9F1+r>Fq&S?b;Q!)-W2z$hElGJ*D96aW22hQNS9g8XtjU#SO2vAJY=*3_&- zb@s9kR$Ylg#P~S^^_UB&-CUajE9|=|g_&w8TVb&KK2r^Il9H028hoRk9$h6BzKlQ4 z%V7k7{hM}dTR${#h>P)eBML{o2Hx89voG)Q0aP89{rsAp4lT--6Cs9$Bgu4wc;U}x zGuu0|nu}fn5EQ!4!q=ClrUL!rS+TBYW-(n3(F_1k(%hl3-`fnR9I5VwN#3l9OGS#J*GqAy+32K8GK!KW>yHE2b zs@JbAQ|bO7l8`*_S)(_l(J?ZMx+wM^Wl9_k)ocxU;ZgJ+H@CljJhb0PiDIdkoMRml zFsEVk?qhP|^iS~7gAi>B!fa2JAA8>{tGJ>E@zSeI;h$|wzKAvx$c*b&TcDS^J%^j~ zVxq#YhJwoB81QJC`__iAkZ8sGNC zjXU1Am;jzYwXUY_xp8T5`PR=KS=R4+bE3caOp$t9*MF89yl#&hhKytigx;=I-Zje{ zPvz7}2#4($^W&6J)cm-A|5%Qc?aIxVH)3$|aS|-~iA}{Tr+DmlOitm+YBG8F?3XH~hEZ zynyDJz`L^#EAb3cqSgz|xcGY~K4qW^x_=Aa>39B9GP&`SH&rGQ&3Q|MJI)5)JH~Q# zo6A&9dYk_axN|jU{%Q=r^&uZKvB_7ZXQgd}+p0T0Bc>t#z6@3q-%V;-h$KT(4~|p2 z)OfwMLO&jM%eJ22)<`58NPOt%aBT%ZbW%v2$+I^1HJ53IC@-ls0h7icaR zf&@NP{KkI*%r|!QBdNh0ej1DD=B?kLp@Gl4Fxj=DWXI0 zj4Ux^U5g(&#P*ZQQ(J6h)RiKbZu%>GAikf8Nk|qnbNm*7NZMX59Bi5*i7|ko;i76L z#PO=b_?7}~jb{8cSvdDrwB{FscE^u0=M~-y-!QKZlSG@G$79sG01`=?ys#8?I>a|` zIlGms7G#9~py5rnn!r0|wGAe1NEh`jPx5Q!tePSBxiW4w{>=LHCrtEir7JgbPnqPAxeeUpJefx0WEr0lQ?Y7&oP1ngwjt3vlcJnUE{z)i! z&Vk{(QwQ^&ULysuyGJ$Go>Dg2jK?E|WbAlq@7a4le^i{jyc&mn?iqlu<}3kMX)uBA zXV|5&4d3vy$qE)q_%Vd~__B5dO`pm#*?0Pf`@S%XcH7<{S9F)PWb#?buXo=P!dsy+ z{uOZ6vSO{0KwrOhBtR`k`ZyP0s#9C&^GlIWmJ{PhcIV2%@&R6-RTwp1p)U^=qg9`u z5g+}!-ZwS=_XIJGHi0JL8ELW_)N5Wo+j?r6$q#h38lP|R3?Xko{r+`|Y1Z0ibi*%` zMz`8z2^Q)WlmclCwRF#qs-rd+xVv``Y?39@j&&Sg$S}Vx*C35mv)M{ zC%%iG-NLvpZO0LmB{w#(=BkW=yre_*7U^r24sixNq5bsPA3CcB#}x}-bPIMjge{as zt?+9oK4hXJOb%w}=OSy|FxfGAF~yhz)q^`Tep~q*O6v2(>zwz&8;;^%YB^K{D^qY%WWX|dLJQh{amo2kZ26-xG-=;yJ+M;krG?X3BdQN4lsv@ zhiTyLLgz-F^B=x%d6UL(KmHD3u46~&A;39h*{x7i$P3-CtH%F`KGdf1|7vjldkFNu zehZlX<5^xreBlSmG**SD7DLZq%6zR8yw=e`&z;6>ao?%JgUn>VXf6o8oZTsjX}W4X2EK= zw#6%H_72)_90AdtUQfvSO~}3xvwHQ*o_;s2J3Q378rEyK_@{Xs{GQUuPSbK|S1>AX z3qQJSOkLJ1bdHZJ?0y*yb@dh>c9MbB$R`#_uLFc=9m+^!zY$CS>KeJK z2F2l$&-H2cHZu?7_z)BweIY(0+e;GSh@ZN?Z}AD8*C}Q(QHlyL(QvDSw|=6k1A2R} z30vN?806&S^tCdxKOkV0^wh;G=X0(xl-@W-p-4`MFImXrcfAmE&iAnxdMHNp+@TtI zhK0ASEzR?-m=u+js+(+M4p_L$0v#J)RV`0H)>RRfLM{kg(|-67zai4(_o=@?#6+dl zz)DYi1s|Of(=_+WH0w>YH3V_8JFOs(s@HPu$ByataJMpKq~SY(X$D@_)^)31QQme8 zsgOD5uV#gR%Eer9o|%k5WyyeMu^s%r<{wSqr0hD1$9G$W8ZlB33fMqxkZ87Jcep*g zaFVh&6mUByhdO7UpSg10j2lhZfY~RC;=dDkNv(Z=0so2#TiGUzu5)Idv@(xw9y)*F z_k=CMICY$Brgp0t6~K>%=E#v3;LjvFzvE6nGwUF;c5Ve9uBXkoB>x;F>Q1~e=*1DwJ5 zc==M^`$3()1nW;yS@;zOx2Ty0(GDlx=|n}Urts9C!j{b&R)Cr1{W)U+0Rh0xL2_8f zhmM%SXXwY0n1kB~0@@YVJOKG&jq$)UP;hGw#DBfnhWVqS3 zG+PdcMB2}4B<-b{yE#ooEHtZ;O_kr2cd&R54sr$iim)6^6#Bv=hmE3ly40Q419qRV1 zV}+g6wHtk7=o93t&aZX^3g$>PLyP-45Er$=804ez z(1<$6GKgq4k6%J7#5zY7gmaaTY!JjlQPv!n`(EV+ZY7C|3)sn>caaJh*r6$5+ytY* zU>OkVLLc`9en3glylCS*ZSrR+{i?FW@iZfiY#@(IZFi0RkfCP7UC%6Q6cXtc!WbhE&-QC?C26uPo zn|t@}es#BMcjwPrQ&TlHHPz44-KS5VEl?&eQ#`5zPCK zjb5-%)OE7?wbr+wJ;hp_&aLVscMqk@3e`=I+mG4@(oGk&#fD4Oi}jio#^DsN3)Bas zhU%m5xv6o%0FK7j=7%@^jTaE(QAjWZg&F;zKiJzQCi^_VvHm4FO3=q7(V{|bduWxOX znh_vUxq#MAJskb>u#Fq9edr{f`>FK~SkAqC?j~AG@2wHM2@!(B!WgEdaL;DkQUl$2 zDN28oC!ADvDj`ZGq|K|iIh2ATUiEsd^m!?6@AZe6G;v8}wK1PXDOU0s?ULBU2cz(C6Oi^Bur1zSn2 zir_Z|AeUT$aQa56dKP_|lrbJ2apD~j`_Rqgn;4Ry;xXzWbP`LqRA5a7L0@7Pmsd&@ z5yuZte*$?)NmZzpygcIFH&@LX_lPo`W~h<964%~tUp6I*v3piQIIw3!c~8^ask*Uo z{u~v*r>}3oDNOU*09X*BLbp|G-4~tUtKj~4c43K0!YLa54?1aUP-qJpF)!U{N;~to zs^1QW2sZnC6q$e?Q~RwlwYAh-;wc}j;oId_uX3P0a$I^fHi?Bw?Lu}mG8SPhY^-lG78b?CkntUsd(s|ncZ+{NS=!j{<_dei@1@Et?i#PB zbvYa%UHe>Z_d8;+C$!0f2ff&WOA5a^l^mVC{1syt9zp%o)Q*>3kmI8sszKaOL}p`$ zEHflTq-Z4k`Hyp|>VN$1xHo*BZS~UJmsx`Qk^I%dRBG3a#C!0Bl^66Vr^{bv0q-F*=_!dYcvTah*&9K{O(~JrFO1mYQd=-qi zqxN_7LG_qbNe-Bl1mMu|YX`e8qSinot%Kd4;uGmo!*80oxE!AXVM~~3(u*VRuR??3 zty5vxlMmjW?~;LbEmD)rnl+*k`U@=Pn+8w&937Bqjv>7FOFPn$wa!+;B&x!-m5poH za&cD_CC|DY-XRGkswS}zEE&Il7qAqnm+Ne3&3*V^RZGEvJPtA)@8;D_9v9vFj`(71&CUs-_RcyMEl2LBpw77s z41R{f*j@Wp4GBbRvItz-HTWX6F*5#^bP$F{qTG1+RWWeW z*XK5En$>=a{2#uib0Iz&?r8uQDX6CnwFBCKZQ_xUk)F0zA+=?2y6uAt;>bq=(r)Jv zkg+-!*@}nvnnKuOkb?z3U=GE@fVM4|Bi9;F2qRu4`&_Bd{yK%*yo}`x$HjAUWM8nc zNuZN`vJ3~tA$iau*>04 zbGY0*pQ6kL&%_oafWi`2TA^L9X+Ojen$6iy@=hTLy%4YsWRc?;7F1c z{VqOc^e_3nOLx@K9RxSxt@ah((%ZhJnu&=?x!;~SE&|*!W{zcZpzpFJFQ|SES_?S_ z?%BdXO5xAOz8@*6QK}2Q5y4?4SZ=HeUC-chONlXa&8~YTBmicuw%~y0<8G%*OqCt? zkpoi&Jsx9ASJ$KZ@5(k_uMxCs(St~FT3R|^PS!H4HJj|g3!}^(x0G`ecK&m`B@UT4 z*PbI8T&cpDYp8uLNhvpe*Qb=rGO0_8LWFJ4z4O;oBIv{S<=T7SRC|@CtI6F4{e#=( z3S_fTls#ix7F>_b9-g{3+_PcJKquu{2Z*;S5o$}m51DSmRk^*p%zhq1VEJK-CKZ7) zY4esp*<3~i+k_$G$icEFeQ>Z?8+tR`4lJy^%0|Wl4{JBqP{(-;P6MU~p~2Yp556Zh zjl(33Ah^^WZ6T;^TbCzNJUn_H`|~5Stbo${OzCg4>o37qJH}gqqw{ZXvkC%?cI{6E zidW-T!xIxJc5B|XIxh2Sj%<2TQHkdIuM<37ZVj?o-!wOZ={xH3RdH{1TLDHpJ%Xo* zmMJ8P8~B;ri0ZeRhv@K=4}xUdJKI~IeDh?1+;R;z>on*BuT|D7bxKZ`5z_B3oez9; zjY0XCk>_}Q_XUxB6rYvw^r{tWSZ70w-W$Qbv@kCYHavWMBEz>}|C`}cO*W;AAH@*O zWPM!7%2^c$`o33UOC1{0BO_bG5S?dJKNzmgAZ;o`{lV#;0P25!=yV}uWWJgfHp!o4 zRdGv0WuRwAMr$#biMIaLDcaInEYwEVSo&wp(2udnhkV|TxeVavUJ1iyY-+x1yC^2? zx$~61(5Pcnrj_=V9_rTpX8f5Ov$zp^Z|(y-jcfCDZr)p!unx zsYz{>Ykt05n~L&@S8~24DrnrU3T)8mk1-j)xJd&(^&r(d_7lqPW_;s|(#noJq|0|j zb2b4pFHunf9eIV6{5}|u%>YozuNzA`8)%`Fg?ZH=a$Wd4+p^okY3TFz)>>};ymI%= zj_vaKDaFFz1F*+B-KQT=9LS=djl{x47-hH9STfh&Mq0=2l7ksX(Meeeu1afFUEc9j z2f_sV*pxoYQnRS-AXYhiboh97oDDZ~(?Tjx`jHO#EW925i5)SGYgILZ&taY?ze#1* zFF?9jwQJRV7OsBVf-gh>aL_1Z$lHAH$B&l;3oy#xT~oOpi#d} z|B*1D-PYXkBn;nK)c2BuBcE_*zofhx=Wb)Kv+WpMCf~L5_c@(qBQH@1&_OF`Atl0& z!~}Xx=b2#$c;!clqnz1x(U6_N80iImGd}d%Y+L=N4`_S#p_2L*>APz9akB zn{h(LBNGwpci%(6TNjB9{2!(XqLnUR*q>D@Dl^8XMJ#D%a$qOY%8>z7qVMt?FC*@I zss$>Tpofn)eQxyM_Dpnif~zCr6QN#j(w~Kas-dmTJx#|#%33;6?wh&4nW>w9sb(?3 zzss2yLM}!o)tPa@FiFVRbRHE=9Soq!{LkU~uTa)GMDT`sI%5oU#QlUW$2&;vh_!jn zU1?vv>UE*l{>p1N{EtE*65+5NxtF_L+d-i*6W#&3ruy%lQx_(ubYF2{Sf$~`Sivt6 zNV|7#ST=K|v1NCR32^d!Jm>MLEs5nyaWy!X>yX1p(L0RRjNymT445XPEq z(r>T@(abdcPHjKmn@Esjw3T28jUa~TS;M9 zjYLXMtZIfN>lz7NZ-Wvt&pV}HvIR4)@Ro!)PTJ&^?+}va0qMXacHo{jx?_gW5IzDH z`=^r2EIv<5kQ-Hj8zaJnL7!Zqwrhd-T&>NC#1f9Z4hQ1YkCIWT;~BUC5!#3e_|?4w zs7bafK5Vt+x95AMy{i;PU}lZp%l6zwUzkIq+t~(nYLZSM)+z0Ykp*)#YFv||pnBlr zU!=F);T=m_sh??|QOQfef5}#hPdWX~%k4QMki({jb0!PVCBXN37cuUo-d#eNcdD5x zjKO&T8H8TbQqqEDq|ipfq5$==RK0UtkZHRWhDt~ezojO)eqbEir#>qq`Vvd-fJ{wHd2Xnfujfo@_&9XeS_f-cr{h8x?YoZcfegK7v(t~WsGvd z?EL=geuHu1B$w|WiC@egV(6P1Lc;}8et;Y z`>V2pxkjoS`NWgm8JU@3;nci$yy|Gp9h67Ee_QCybW1Nu4>G8XT|E%1k08LpZyfj`TvL~lmKM>00oN9X_kuE<88WZoo&i;o(MD0bMffV4ezvP z0_{J#sV>-P|JFj?v6Y6HCEbnC5Rx}4%u65qC%qzf>TdkxA%YR?q&Wsg2C*-vA&E!RP*vZzk(4E{;(21_{4aqY4Z1OJ2+qqR$zk0FKB*1Ll30lgi(}T2Xmu zASZY(R%C{=@CkX|9V2oa*lVH+r&u~TMvjxWu(8f0=UY<~&cn!i<@2mL>N|}m zvwA<;Ya%6I@Pu4Q(Ca)ZAhk@(E@J$TG0pP%=LaxKVMD)pm4py5k-;4V)Ks#4|}3 zU}V&NIU91Q?3^&=uSHiCsD01KAZGm2aQTT85Md!=YugaBxYZk`hB{GWCKGj`r|K*% zZh#GiJKGoSbMJfLes*^}FN63|uIPT^Qs)H2vd0xmz}A7UQ#eT5SE}vY^5x@kCy2j> zOVY-INTkuHs-y&|~%vL z?N;H_r;%`L3W|WdD(mH~=qo@yZ$}U!_KeoN7^m9ZfrHZ$PQA1(?OVpEx%s~{qXq)! zlWQS+Yrj&vXhfm@c1!z%ePOfvG2etv)jfk{82B6PyD7T7R?kn6ZI_s&gPwGENmWY{ zcK13B;=BM%w6bXs95aP`)dGApoloO-n6WRA507UTw|D7gSxRnGMgviBxxi41^|Fcz znNjI{{SSWokIYhflMCb+`UBp$Rp^|36Fqu=;BO2DVo(N<-3G#e@Jp@PcpwzdkKaU= z-_UiP21O-?cRwcz?iW0tx&#T00;LQC>C8HAZ&eAundcDmHYvPchJi$++H}@`!NbB! zUhwl#^Rxn2dfPnFd*Hb7Xg^P0tc?TNN2+^_?63GVJoooL4-cnEa)$-Tl5*PTfJ<`3 zv-}(9*4?@Bz^0Aw(woX>d^X3bblrcZ@y*AS;8hHT^P)swPjQ;y1gbv#2To~(bd;2G z7uncYRRd&GcK{%%o`d_tT+uJd1F~a&o0~$^6E74MZgx#n=wXKGNX8}U5mt_i#z(7- zu_eoytm(i{bxj~_qh$DQ6ZfRu+|Hm)#|+zJ7g7VJxZSe=7UIxx7?*nRgk=z|I7H5N z;!$nKO+!nWCZy{t7T{gbI&x@i*A!Z!MkSq;loZM9W|IYi6t;?Gb2Gpv(ockh7xvr2 zFwZYg0;_cnxLXeW(&QbGuuL{B$E&&u$oh$g#WQoCGkUkZt#VAy$4?Nn^FDEhM)^^12hxjnA`NT0EW74hTL*(w!qj@f(I|f-33d0wLX|N= z!S~Ha&`x+x5@bap94K^6OMUhWP@XA@ESSiYZWrIOW2|c z9j*G=YeI_CCdbTCO5~6b>Y;eUI>C0s8skooGyzaPIX*TS-DkAN)gxcj_iJxS)2ly* z#u!#RX7xU-$}QnlkdskyJCdIM!_S%vsfe41LK8s}pc@A5e$F2*ZfU#YVfmi(ann7H!TsSM5PpgBEq-uUs73 zUg>$Z`H?ce9_rMg=ev`6_JkR5xjD;!j954FO5IO=&ApNy%{dQxJ9l$-f>Ij=nE%-l zelIDlfa&HHO&;ZL`m#t7U*uA;08F0h{CI!aI}rG2Zuv{g4kr5eKCC}T>M8U+Z?q9Q zOes(ZFl_O6l7oTrBO_w4QemY48DWm-kn8@8@o zrEcqwB7RbC=OWU?Hl5osO6r`-j$=!;%YCwO_0&C0dl@}#?Q&5|{kUONMb<=blcmFQ z?Z%PV_czdy5xi?V9)Oc#YG6{884rF5;FhkDC-^_~B!dJN2JT62Qq8CGqZO zi@`q<$i{ca-&uWMIiIFu-$j1-J?4svi;f_~T^%W^s;ev2pJGMm4`wHdN_d+Wc@#hT z?8Zyv_@Y4x@ezq0<8Z+Ua}zt1dF^uF-EC9L7=sP4r1NX#7JA`vrvX;Q3wmwt)qp_G z_LGU$-Oi7b&g3!L>g>csDkzym6Y6o@D*{iN6g@T6(z<4NFyY;OLqG(qC+-d&eqA2}`J z1{AB-vOfNz*INtfW^E9di*v4+=Qqp*f1=I1Xx-Q5yV&oRB^ql7A;atyh`_>D0n~qe7bM!WE6P6 ziUm8|XmH@#iwKE}r+9}y3F5!?#rJWLnGpQaf8AbOLc>JJ^TN~FiG{H^$2osvsbs5V zop*U}DCfao&S2^I$*^K)ZaqLCXi=%rCB}!Q#mR0-byfX;V}Shuf{KEYYq88R6&lRo zP~9vIf{-HPZ_AfWd>Ck_WU8Upf+iAL$`3Rsfu>MLSMTBc1wS9Dcbs46HmukA1L1L! zVJ0>zo){vJQ?87U4pi;W9f zTCE(_!I0DstouK)4MTZizmi@HO3yPDwd_K-fz|2hNY^(egA*iJPFoprJ;a&E&F&!b;@pjeVc8iL#rY{fI(A~hW}Y{K>XA{7`9v_oee9ka zI&TrvP_IxZv**4h^#%!KjC}57S(vD`g=Tu3yJ_~$_Kr}`eo^T)6voaZ|3e1v`_c~i zFmha{7$qh{EB>=k>WWNi2R!}>?VJr~{Hyt>1bBtTvXhmSjT)XHF2_XnB#i9+4^};H zIK}ulT;JWdnBv!pP{#~+m%$*w*|W>Z-rrO`7!P2;^Yvai2S`;rNYHpz?Ku>cNN{A~ zb9DxEPui2bAlDn%bM%XT2Qky!j#|IGn6H!+%c+pjGe$%p&y!FP+~?`n85!o`)$n-v z)N>Dy_TY*RDejxK3*QI-204zsaYfBU(ZayYHyy~l-_-qK&*!J{ zsXE^zW@7%CZkq@&yB_E|PX5^is{ijDKQG%;&mRo3ur%4FGzsx79_X|7`1M^axLSbyk3uGh= zC#krLg=r!P5nMPCcMDpyFam_IU`%Y?-NCKIv}Z?Ko2up3NQNkNL=Q%tSn7OKy6kox zsWENDa9ow53s=_fgpxiRFf_F;7Z|_Gpqo_7xU#=2xW{-lx3uCOEptq%+gc#_rk&r% zx)YK#a1*U|0*xZ9&%@vm{o*?be(apCnd(2t~r$4rysUty3U-7Zyt2orlckL%b_jy%)h#X$G^w% ze!SkShzkq1(GMzQa26k1#(W-3)391SRM3^f)e3wo0`3$$!7K(D;2%I?OL;U5zRv<7 zPKr6Bm-bHuMmGJICmz2UW!9wwVRcX(Cm0N)+;5A3K8A)qbzypl-&}dUVhKRGT^T#l zHGD`ci$|0lcuom0+{u@x$R|@zJ?J87!t?Aqf1TQzJOUS+H2q=t&M3~uG-9uAB+tcL zz6kQ1QX%>ot9rHh7RTTJ>-w`-BH#2LYXXtH@=slO`(j`71cS_;*Y{gSE+qK>8E#J! zf_||zTAf}MMhs&+HBBIoj>Zn_^NXMO6$M68Ag|Z;seAB#y1jEs+rgdl%OvWgtyV9? zxzj-#yLs||56FWk|7Jb`v!XA5!09}L2kJF3wfK#!?_7s=@*u4|F~RlND#V|o(mQhi z>6f+yR5x*t`&!K0yco^cXI=PXe{|hcj-Bc7Kt}h!lw2^!mNZOLU(eaebV&AJaxj{< zLcQ!05~In9fI^Q6#MHyf1SkpkqDIg|t27y-lgy$lSbffwa)!7}6Bgv8a^zp7q`9x> z*^rtsex+BBjz*3Oc`oKei!%~M)$r16oi7j6TYhMdtg~xu&`d|L7Xb>kSJee;;d@A5 z;V~=0d&R^rV%LdCt_g+F0Cl06g#dpvI4)getj3BC(z|&nw#tAa8jIrutK@Ys>fVb|(rnBepY8t$@<|%fcc&LE z42nhf%R9Cu+VI*3p_loqe6{X9bfWW)D33F@3$V%HQPegng@x`F*s_M<*!# zOFp;4bX^n!laNVn2~iZCz}Zb6w|P|-qUZO8Kjb7w?zv&yo^_bRxMr*^d6)YPQ^wR& zkrUy8M#>;y@+ZuOChLE64^2fFT?afI5G@z5AL^uD`ikBzz`C^9xyII!3#@+tzn38t zUD{)XuErVK8rwlxde*;kld_#{WrjF^OeeA_u*-9&hi`hH;DQBU3&U?-=JUCVl$ex<^kkd1>RA$ zM7kQ&p!Ta^kp*qbsTC2$b(5xD@Z1`nqCyCABv`+WF%n;~9*_=8F}*on6}Y4il)^s| z&4tuERc{17xRA5f1BR4IVV{Sb7WS6ARVF3LlA#J5z^-cxI*dfR^SjDlUThwHYtxTkhm$;uYzyfI}IC(B!*I zUL(WAN80%F(uMgz4lP>Tqpt|m>mIHUQa8^(kD@77XN7v420d{7tM4x7S2Pd@;=i*C zEssOn+Q%8xoz>Dp5K;Ko8BV-A#bBOT(scxFN%*l<*rJ|HO07Ughsqw4`d;| zHUty9gO=7dxr1I{VrHh98zla646fGpEGK0UK1A z_1ou(6BQZRPS$C$F%Pr~(8Qn%_E72V3u~-pJwv}aTV9X)N8fT!&D-R?6}!AU-G$>P z?N4{tVJyBk4pe{-nxETt3N#n(9n&cW<((vt>v9+JvY(E_fcid9k{vhGOG`OKM$lJY z*+lM7%e|et8GBlD4}I)U$SIvcx-akQ9%~y}G3q>GSTF2PqnUn-1|qbVQ=s|R)rijZ z$=^$bwYmrHF18@e(puzyhlB7@pu~OkzlxZIeuBbhg?bH2^mBKuA-AV+8@2wJ!Ptzl z>@@FT)8E~OO^IAp1D(q;plv|SF5_wP_RK6J0eQ5`reRt2liMngi&u6QTvyOEBvxD5 zV(jJAI%ac@e+{)s9X&uCI953kX`pomRjv91@I z-2*?8wyrpwZSg8{cW6We2+iP&5qo#qT=n>pl34@}<%kPf+ol~F;iLr+<*TU!2z#SZ z?8Po088@>sXdQo4GE-YX66(ec#gFK_K?mE>{xq{i(UZ#LTg7(fj_eTN{>XX79veFv006y_}7w;{QxvcoSCi%FLQ?GxkKp3E;b@Oioq zt5xN^9H=lxJ9NX=o(*|6C|o#EH*2a=mFn-EMD3XULhKdiPqO7gbrCXMh>ulbwXK0R%CxgT(M zc$#QwAEk9~5dGVr7d+b47`s4rzZ`Q0w_`=+fovAJZU@ z_E~lVljftaq$)~=SPm!=-C+~2lpCGdK%pU z+q)r_|H%jWTq6<++)(#J?K*2;1EI;S{lG)0p*jnd@4*v9b{(IY+b*Hby8{=makTJ$-+cx9=4C&bv>Zv3% zr{V-C*0j2%lD%%e%rxrj$AMyYL+vR0Q$(MujRuWhV$N!OR$Z5C-C~Icy=;dpTxFXp z71omeU>DZMW|B48K$O=)YUp{5&tGR=tWjGWN!57Xc|IK}_%We+Dxa? zwd|x`U7khnY&{h#G^PwSHFcTqhTcxoV~iP3j9FJzB>ZO^bqhBkWZsZI0s`!QQtlaK zJLP!)k?8~EF)#U7*HaB-Wd4YX4+Ijl>DjiPi4PB*(r+nR&X91=7mOvxXMG8Re@Gl< z%A{g$e{JEt+nsg1-07V;4I#O*8F!eov#};|$nb+r+|iP&7RYG@I72qLzoAV>-JULs>`!D;LBrje z*HiLSKmpaCheJ_;nJb@&1W2C7J6hiF&u4X?@5WQ&y6}e2U1M?Za7Km`X_H@VDIsG} zq4o622{=VX#YY~mjCNl@o$A}$dEdPiy>+6tWz<|S)_=c%FwN=d>6M>vhX)QM&_TFh zbwV4uDn&=Q#qJV7*;87zt+n0vqv6ukJ(TVP4IS@{ zeAhEdU94@v87HpU`PB+0yxCdn-mTMUzgF-2fqw&(H}k~1hAw`2f@PfkGpTj;2lzAj zJuwP;{xZjxxG2N_uMf;b{Ef+UNjQSm43UtLjh$srjs9_U3#u#=TtO6fr&;LwvxM3U8aW^`j*~G$%XLvRq<>g;`fH>?>1kN?-bY zgiCR|HMV@_;nj+|qAc~i zkR-5*6uwVVSL#ppA$gRDA5lE~{Sz(vsHuA&W?WAh1B^#F*#>9XD^gQ6&{&Us|X@ImgcyV&o*- z1df)oKcex<;xc5+Iv8}C8!^~AW5#gX$Jq7&!AM$BB~}bRX>NA_R;UE0HERDG0^3%3 zK)XtCT>4F$n4w|bUpKvq+ml2pOp3IRrZH`na;pR#r}^X>m(d@^K?iUHsBVWfykr%q z3*)c4D%*P-UKepQHCUR>h9N{eOHvqw35CVEkh1^{IP_0+4{JVQ#`%54bXhm-yp(Cn zIE@YLQ!qB7`iCauoB)U$k~cwqS)a^{FTK7YVF5$2NVDY-vxRbTO=)yb;}`D$89e5A z@uUMdV#A&*q<-S^;xf_owp9DcUYeL>+nL<*j^*jl#FNt6U+WehSwFD+d|l@jTOD#2 zVQmqRgkBvtW>?sw@8-u@Q~n91{MXQgNe?FKwZnaI!PE3V30XSM2=>LurRw;)on<2b z72I4D{*{8U7?kk`Ls?qXcO70IjmF1GELcP&Ql#2HDs*Ts+B;Ef!`&o*{-ju@I7&{X zMXuDKO9cPA{Cv)Iextk$dZu`2c=V?=mLOtEfjNqJ2tf1hXLhOJW3GJ_;Rt5_Kn&OT zAywAMK1O6Gn0*Ps;?P zWh78*n_)N#h>3`oSg2*h>MRFvZg_PvNQTy+#s*VA4ZmiM^O}<4QBVxIF1MRo(;b33 znROH%)S$p?@=NM)d-2^T9HVZs(q#=`AJ!}m9%F;lI4*DZ+t__)}QX|9+MTLK6RslWu7yg!5WmegF!qz4o? zY}Ner$p>q>dQ?{>?1rQsM1*xH6Yv4VXkuiC4LnQg*;td2_z2nwTSZYf{tZ8pl1FE# zNB`y*>8#(|Ej1yIm~6tm0EM7xO)?p(QrKa-U9qy|43gSCxh{Bt7T1J`XLL&EC-_o! z`|5clM$*7K-kW$>ng#PQ6LoTuhN84}awafuu5Urd^gfK!%*0fXVndy>N5sFmG>q3x z*12w@^vc0O8B-C~#U)6e@00`_%pD03WZ#NnbzJs@x%4#1!E9FHw~CKCe;|+N?dj)5 zUB7x1!Ws2wW%PqOCDhxws|vk^Vkw{{k9w^3ZK1%+-?qDjRW10P0Pq}t2u$hTo#Cpj zdZG~vjV7Q^oy-P@$wL;^q|c+n#N5xa_4ZwMzHf#%p>CB$gybvh_Xr)c13r}#8En~H z@IphqZ`}C@luL&}=|R=#@dM9VV|;xKi(b>6`9!oIY_8V-8L|JQU)f)gPi<8e{wg$D z!2bWOcGD1sJwqhEW?>o6e}%G{CJP!fc zg~`KtyW_KSvZ}g>3E>pr<$)|IC@h9DO0sLM<)-%a{VE zH1}r$c-P=Oe&;XVmc%tOQa)T|&K&OmN?$rvq!e6jl*FyFiwr9dF*^+{Ekl3@6jS<% zkSmumAq=oq zdU_Xfd^(Dno^e;<^QiiW(66V<0X*YsEQa0`A8#iz;kN z(v6J%P*bodsZ|w5%2O;jCGRUyZhY@j)&i~|Z>PN-L0KnGsqZuAmh-F6mVvzL(l-&M z*+c(R3*hUXyJ&z8b%D3)pD#j+dH6eU1Il^+(1US(Y=c2QGu8WoLGFbk8NqzX-KqkK zb%S(txkSO^C|@KT)ADV|;kXEljUDmpetEdP_91>|W`HK#h${JtK7|%xzfDR;h7SAY zV4#PpoZi*LRM*{>jJsFkIZt1dE09O7H&~BZ(XfmrWwRnm)V!6Ki)KtWL7fAh;>(UX zjJ+LyvKV;#L+AK9ZDu&kehVwn_6feHStgY!Qh&NwMHx=pWlWKI{vF`Jh3|rmK(FYw zQHF#5!;2}xC(q44V~u#Nmnx}^Nwl-^3~b6Q9^2&|4pp21A?)Q}rqTS#rpi{I%DRhi zV+H3dHWEQhBdGZLs@sQP(UHrgL~?#=ENSh#=Kk1kikpLpltam2kxeO8iJ6Q@=X-_3 z3s|$Olx##al8&9A+*9y4j1mmick^Tf{RF>iY)))HGn6M?_#Ws*L;BQn}(i( z8Wk>-WNC^^OOgyWCDbpcr&$h-qEeXY>3fJvd(w=&AEyVr<}3Zybh_YI-R_&zCyiZ$ zBQF(~FmbUNbf*_La}>E8wmJ7D>wP!ub=oVAN(X*R*lb9-4kY{=LAOgRz&{>@-~UyM z_TSUTzuqx`T zXNVW+1%vI@TXeHDZ`)!qER)$MTe!=B6z+g=B z$jsl-OO42;0WmGI^sm(7Keai-uPH=AM|whTgbp7dJctU;(@O=LNI30v^xU^9Ydl6x z3(G>srA-r*f=~nEM$L>1MsJVUjJNZZ5>gh_q#oghbbkF}Fn$Xyzg_^^jco9Fsn(C6 zLaOU}G~YLRJrDwj%CfO^V^@r{Z9HU^Eg^VbBo=Jjp9>sTrpo6qjvgw=J7 zv#(91-#c@S+l6oD3GoS&RD|PMy}FBcKE|yRC zvT?vp2k4>uPwxCn8v)vrL3#Q5Qa{cA_r_3n*IZukeV71P3*v$<0p_I5Ztzg zpv(|It;A~c?5x?ei6kW%p1RcZRR?)$oSH}Qx%2HFYdJ6)b?-65L9~-CFl?QqAjV~ObGLm?Ip6t!0%hYBED+bKNq~ATma^nTL2cue-@;Dcc@!jnawvc;foL>90e_C|vMtf^e zn(HV!>g5Tq!6y090;7oU`!D?wDLQ|tv9J)>AmH`KUQdycDsLx7&c`VZ5ZQ_gsO+|a+9gaU(x6snayZfFmqt&ueS8w5i1{_d(avZm z+rhg|d(>E%c=UX^OC%_6^Zu$*t~C}c+CpK_NSZ@cex%bXX6Pvl5?9VM%1vLHmu^^ev z&sY63r}1^GJ1i+YDjWe?ieHQ+zh8-*k!yWz-QT77+fBe= zi2*@PIZ7>Kgni}3B;%(Ys@S89f<}M)rTI>MyRq@lOG%0ma(EKSbtc3|q|NIlOsbRf z-|NXMX6Ioama56){^Y`itpjYrP%B}kGZ;T^KmzfMWHw6uo@{f^Fup@m6pk-vAi?$7 zT;lV*n;0D@s=4JqgJ8a|fT$&gm)CVZi!!VN)YB7fu5!VNk8zJE6_X9(0S@CwVqG5N zQD}VGm!ri>GMv%eG|*kmMHePm?}KpP=eMl?+4K?$i^+(4ePPvQ6GIgJG7U$4l~IN= z0h-5Iv>Sj2erE~Z*fZ8TnoptrrDku`9)ywvv~BzG{BVZ2cs%ZSyM$;>zeEdWR;e;* zR%?aHAJXxN6PPV?ELsnmP5eZq@b3`mJ#T|Ez?S}s^C}%@lqiDJ^Yt=~2stnJy5ngd zxC?C5VfOL5OUO}lN9%$C2xo+W_p4zhdiS=%$keggP=Mlxcv(b@k~KWMnYfnJ-14ye z5pP+1PJ8kWeiLFpe+#(o+wlwi^ooOG);Pu9J=@_)y`pE4 zO8svqI{+CQlB$z=%z>@+U(~sO&;A_^2>#C$Td;;jL_@WQhxTHDeOD_kR)3MsgQURs zJ|)-R*BC6`0BQOkf@&Vmx4w+MR)FLrS!n2Fc&wxMmx~})?233JN}(e5(Jd;maO8Iu z!zWW|d3kQhN!4^7w@(O-`#JQp3`C)qg<2;-BWW31(7=O1WT)iFW!Z@*W>>FOIxTTipdZ}Nol@8G1oR?j#} zS5Fu9d{ordFt@f8tzr}H{9c&Szxo0Y-nBFvZEH_A>WS_-D6*~v3*OQ3Jh%*{gkk;{rdd@@==EaR%DL$@wnk!CJ zlsOQI@D*+l&Ln|WuJn5N#;C5oh@yN2@f9H@@>;7%*Gdq{(7=0G$p=9OrN(t4W0^d^ zvU}g3xHyR6QJ3c-;0r%QedRBztdtcoQ`vTy<9V9pY9C-mFtSxbux?`F?uM6bzlMor z)FH=)&KK~iVo#HEq7s#aB%0)|Ri!35SZ5^UxlJQ-OW0>O{3q+jwMQ2}k@V6|ml^cX z4&@Q*wKsYA^p*%bxt@2@>2f;}(nDhs1oe7R64jGX)$}-lz6rgMsG(MXH#Nz{b(Ma; z;E^Xc27jGYppz`y?AAW9u>;07(?xI%2Lj3AY-_4*=;1OI_FJd2WvPOU=Z_ZRH9wrR z3#B}M=o>(@Ou|^uuX8Gi81uDfqrsTs7t4w2hG3)2z6!pC%(bSk?uyKaXo#sjf!JxC zVbnx0KCZ6Z;g9C&>@HstUhXj*mA|zY*BN6 zIUswGxm}XIHIh^}9C*zEuIR*ptJ&j=JKRZdvYragQc>h8&cf3}uvVhL%+Rf)6*-o59;o5eBv0roFd_yY$;GQ%v`}bqqk$^z(^p;GF$2RhBnf|{P zOdgG4dIYcI*M3rBsw*nO;4&Ioa?CMsi3JYnQZj9}%}*V~lzXzUhg*MHR+#wob4v;hSGwL>x54TT? zxSrRWoM!blG=>{(ayTiUB~18nF*%M`&Ij~nmRH%U#XCU==zp*57%1P&5rUhP7&$Ar+KP_F@;VvxnH8R6kaa`=HS4k>g=PN;31qV%wjt5b=6)+6nn z``s{)4BY%h?k;n0N}mC<&&sGhs; zhb-z7;YrkVmqKLxH3=kTpUG!BC+UHH{-lt_S!~Qx*A+=?g#_V_?FtSEE7+QnE zuKlK>fe=pZUNP!w@8$qvQ18-FFvLe2$a{TiE`|ud!Syi0%LFzSbm%uSGJ!ZgS*DUf zJbiuj)~tONiKdpv-`3_|iRnOBx_|`tNvZwz0hQPbiwGBX?>nIgCGUi6Uc;>yQoOuW zeYAa2NJEF3Y=zzX9n!M1Mo?0qhg3$1rGQS#ibqMtQ6;AcT(9JtxRmU4$%cpHd65AH zg2EAxk{ZHMA25&mm@7aJx+qS-vrf_VYy&a%X6v|rGls`5p7*xCqC;#WSo{6&B~F#y zhp$T~h^i4@@}=~r6`42xZP-BsPZi>3a9h|*9-;vU2ey5-&Da0O);mU5+C*KuJGRy7 zxMO#0+crDw*mlRZI<{@wwr$%wyT9|jXN>0^XVlN+*S<$pty*)=YlSLBM<-P39E?(9 z8X(H4#Cg6wZrt+my|mzR+d|`5pE6uhDmt#Q8S(PYG0wJ~9(8AKc<@Kr%tWHY4{VE` zj(e|S|F2sc>))-tUi1GM-v8IF?F{`4&1}m`)I&s=kCssRV+07tpd234j1g20jB6*U z*^3jyp)?CQL_F=f(L4C_LnnMpzloxWZ{ z5+-61iI(18PnDQi%_)Oc7E|tnIMgFXPipjB9*=!VcTKF&KNdIT5zNSXI{eQn!1B)D z2z8ey*gtK!6b>9>&zuiGVALm7?%uP7Mm8v zR=pPk^pqIB8@l9K2H{Ee?LZ4HVYnOyhF<~>Gz&1FWY0!9x#nUiwtm;wy-Il_5t3P1 z9#DIaK-$GZ#u(yJS~y}2`nWg`4f*h4d?h6!f}L<+M!2UPVUD^>)J=vSU7|!r&8rad z#_f14-+${(UYgh_WrzIJ-VjPR7l*30=xZM7{E2KA%EC;LT% zy_ZvB3%yLzEvPavq?nJOZJR>!b$H|ZAJPt~MN%=mcG01*Ro8SBz>)L5-HZkVo4FvCVA0fer z$*;|RxGR^h(g^LV`L4~xQv>~j!q(1vaUHP{ynAN5 z_&wk>=@a)dajFeQVV|V#!k)R-@=2FB-1WE8^@;lZ5`qHLD*XUM@g_oia)4yDAo=rL znOvdeGNSi+tES>zM6~&a0f$8~A_wt=-!JzyK<`8R&l}sx{A;qR8!}Q!gnXyAV%_sE!mmFGG$FZTnP zwP=1p)lg~pw{eOCISPY=~ zU&oDY_4)aU+0wGIzTtbe+IEiLB&cddY2|H8!wurJNN8_<_lS^or$SxzZS$rC*wU>F zDT!z*=!QM-`1pmN3zEjBbhU6GUnGtx$?;qej~F7ybKo1-8eObHEAN#NsHmze_{o2K z>v!|h6#8?vU!qitV4YFM?>smZ?4N)D8vBiWXc^LtcDWa;5cufxmwaHJpNUd048O^+ zHS`|oSCB6VramD6JFsNd4v0U_v-tg(%n&pbjf0?A)3kWht_am_>|XyE&h4nKo=tUF z!g(>**3|kN$xpMnwGgBxXbTdgMaVD@F2q99abKJly`NqHpwkAt;r6p0X?9NT6D z)Wq|4gw1*c;`x>jfaG^eX|6*p(*e|zk5prC0Xs}b2A9hikQ79hC?6l6Vl-~lnh!k6 z`3>=k1VMPPV;}Ijrw-`2%g4EI9++_@CaBbwzL6AokxVS85ECTU|{3BjCE6FF0FD?lsN) zX0tBqPi}R|b4$lQaFnFp<+8VAPC%gi#+OZQ5N=U%8 zy7}G(-^DzQm<52V0|P}WC2YU?fSN23$g#cGOBe>D%cgdJG(l;82WTGc93;Kl5Z;CT z)q)KBDw&;>2&+yeQ-*J8#*?U%6UH@CKaV1%#bTuZ?zN_hx2bVK_r)u;<)nJ<$DG{^ z&hirepv0cd-bEvjgh4;`C8O9@*dx_rYiYTojS(~XRs*xcL7I_QV;6{H`ti9>#h4!L0Co(%3{efj{NgIp}oxrrjo6M>tiII?9>D{>H;-= ztKP0|erbXFvpx9K{A|C1ZS#+!7p5Sz(JpTkKMs!_A4wT!7E|SfY*Q>DJPx0tQmZ6u zFXeQkJ3DIxe81P%)z_oYIMGu}PixCB5@u#Ww#Dnssnev;shDs2;W6O4d^$iH=zmJu z?H>aFcAF7l1lG19>5vs$C3k64Yceqd*7#C40Bu9Lk zM~Nlb@Cu+mC47;IOOre_`6(@lyq8F##sb~J9&CafFr9>@O-o}9qBi<5u> zL-p8%ZoO==Lze!51P=?jf(0H2PnVg~Uoe|a$=1}i?(}p~8gk$h<65wkNOu?!49(d5L^G(G%My&lA zI~u(|QBt|+z`h)I`{+YjqLR2Y`NqaoZM8(d+S|zh$<1%u`0_C1vKxUl=s`zMFQ!9C zq!8uA++D%RW_6qbf{MCdKQ}Q0XlTmMmsVLSj}d0Tcv$c@X^u$R-)(iUKTR*ZEA`c+z1dNAE1q!@_+%|O@{?Tz3^QgJB(d?iPu* z5dV)^1ok=>P$W6COBE#w%>)5Cs#JwT3Ubk8-&(6IXT^K`y>5Prb`5>3WAhrv^*Xr z{@hn&js-m5173m1vVFN|-on#MvS#+JPOCKT$D$ztb^K(MkgUx3c!XU(Ji6mIsj7Be zMo7EyugBdnU^`Aug2;fy!JEPDFu0q^m$)k@DCh?#a`TOLOzYB8dDh;@&KwHq7lZym z#u2Ahovzg;__hZg_XXMz_b{8;nV%^DeU!weggq)MYWBujQG#hSn*zo)Q%+jk5y8Bn zyl$_rZpdZR0>8)!46sUKw~;3%N0H{iUvVyOIasM%t=~C5C<v=-C*yyAWY2|2b; ziAGW)h001nC=Gyu1l&X!qb=vgnqGrQF*X@;ds9`K5+bbx40g-lpyI>P)@a zzv;g0uADs#T`2|&v3@+RN$ukmPp1w>;)F+jQq_0|9t|5Bma8>^$Il5VT0=NfIpiSePw0p@xV>wR$+l^tJYw{ zAUFH&tL9gK3lyP*I6U)%ZyUXTIIcK5!}@|(<{HnbT5EsZW%!Js-Ns*HU|*Ad!i@FG z0?Vp#9gS3Z*@3=v8w2N&OV}bFcNK%CZ6}}{nPJ(h@yiY zK5p1Q*Tr#$6TGNR4Fbi|C7Fd>E^)&UA+b7A>GDqB4ftIG6J+jnf_*+rvkstkr!ZH53N@vV6)ph%3?e96HF7>O$Gmvo{0U`7bLWjLBqD; zNV{H2u;9&z$lO{Hb~8j^n%cw?x|>&t#o&QoN3F!et#n(1k&aFm65%_E*V}_aZK6{vb*DQER`do28`N_r zt-{U3n_m?WX9jreV5q!wx0KEo2HH@k(iaU~Vbu)SiR;SX@mQr{8K6qC5k($I24AL= zZqT9QxB*;>%`1VMu)5waPU~n8rvp3Pe*Tw5T?XAjzoIQRpT;%c2`=awJ98$0YTlqJ zyg{yE->@H8FbOJ-`DN#uYV&UNKsr7tFt42WFX`%D#Q^zSV<@tmAN!{h>enTL|JmJ> zJOSrnTX1s^2_qwH8oN6n_#5d6@aZ~cM)4rwStmEi+TQ(p9i=-Pdr7Y8F$Z)gn(s6J ze4|NithrTd!WpXg44s=h;iseD|7z@qWB%J8t2qr(!2Q7rx=ApxN$_>?RsPr%#la=h zZu@AEfmsu;rv%;}$cW0$ez*%`_@>a22XmxVgo^aD$#K)|AVq?y{&3bnuRp#B*FY-L z_GQ?3yN>Kj%BRY#9}I!{MOm}7wL1(WXSWw85jc(z+!{+hCCQX}uP@g)rb{ahejl|sz{<>Vwa&m$%8|odYD` z_#;Y0x5;)3gtpx&E3rqNJ7^X~STYzlYXq_D*NgN4P2Imp7cpr2$h%L|ZwBu}NO1({ zb-j;QHo}3|-b5Fy;-A4IKw2$jm(Ndt@TqLf9)@JX4Ka|9qwU_aaO*cwv6DfBlzBZL!<+;?_lAbr+4gu+YMT-G;yA?={SMD^pbQc70-_Rk+#|eq zu`rS?EU)HNRN`RU+NZzHV#4?_-0 zuQL|;dBPeMu>y2Yp-TmL63^C4fBX?7LMZ)Y0$7m?T z9HgWw!5JbQS6*=wLP7AN>z6&8)5C`Sa|`?STQZM z^4@hFeqe9CP9B}*>NThgjV{GyHdOsx4;5|3K^oZAQs0WW z)0J#L6fpH)*xxUF0@2`Rsa@Z>L^L0(VqrIVR{ixBHAI)}ve>bgz7vaM>T>>f`uoFQ zwYD^=O77^Fj3d&xw$Ce$q1DR9O<8s)a2(P`n=N90NTh`P0QOXFGgR%YWPz1-b;&Ww zdD>53zmJ2{GR!}?a`Lxp79toUo9_#fznZGBJCBzwOvb&lg8jssZ!g!Hnv9H0N)1wR zs2(rYqGi50QJk3)kJ`20WsjSV+idbB>pGXTw>eS{7Ge5GUAsh$Rau$&?DY8I2#8}E z3R(!zs`0DSqDtM^tL?f3QnSD|n zwzd48!ux?ben!)BKD*K^$E$3K4fWo~Vo{*=^zzy?RIZ_P0L0d*3TEoUu+I|Z5HVW6 zyN=KBqGDh~c{GV&tdb*BZ<01lPGw{E!&fDGTIy2LaQh)}P`0t6rQ;B-ZYHr<2nH>*B; z`Hj{**VAkkIXR!qI%qO}$(jfo)cVSl($mUlV~$%R?vZz=$jEv^C1vloZ1S8<1Kcq( zKK^#N(U61nL-A7z|4=!G6x24@GEWjzf%jtj}>#mc;^sveHFoW zsoi8lQ{#S}+I}j7t(V0iU_6ye=?`*WN=??&1sC*>D)pHyQy1bI( z%2XB*ZYOu2jGr>SBw0CbW3ym3$?2nSDEGY(cl`&62VP40Jww1F)t)$d9p1;ysi$nr zn<~P@F0))R)V5#owt}^g(>x)R=N#zM5FZ>e*Bzd8hS9SnO;K$|2>XG>BJtMO=SQvc zg{IrSoE*Q~YbEn`)9%b4&zMkZe%m5RbICYuw*$cv!PEkv|HtV!_Aag1=rKdyerefZ zpNOlCK8pl?sP}j97dp=Qow{z5s1}Kct<(sSbp-RP68T9)U&b_vF4e@6fFFEhn$}$(&Mh}V5QG~z3Hh7N zc6n5@8bcB>fll&qP~iRB7~p0?9YDcm%%#(-3WyO=S!h*IsF9SOwQ@H$E=XtJfgXgk z4A`|XX-X}_4mdC$nbZxrflIKcYLkSG!WzBYkY6zH1?mh?Y9~UDog8*NvZw5A3Ql?X zhjmbwGwyiACljHIW#6U%)<@mi+hly&M+r}fj#aK#6KRcio9PC+lf=nIR=Pbj?|XI0 z>hx#747{mcPHuTur|TNr7$07X_Zv zn7JL-$Ysp8?9=a-{_9olc785=o=X6lx9l6!dnMOZg0^Mxw(?eo2cLm|)zVA357#vQ za`|JnapMRAV4eATsjKrx)21^TZ{6;}+LM=*H+;^1k>sy_tL5Z&(X?D7C7!ub{A8seSTyQ{|EffkCnVwXf+Teg2nCG!JX0JoEdDSvPQ0I zdT^fp??7__zrRb6Ti?ed?E1K{3EY2tuIbCCP8ek}kxkO5Ba<>#@yC6C4)Mk`GA`^c zumum-pOfWSx2%F#`GE9}$DMU>1Od7Qv9?*c5N?Xe{anM7ecqaUKtWVs6Ax8AJ0FA3 zc8y?qf~{1n{L4RW{kh+V_yoK(04mhHFxS}QaxlCptGrhoSKLpl?iLWoSOEoO*)<}#^<@ilz+Qy5<_0lkHZJ~e&tUX==u%$fUJbfXK7sKV)~x|GcNB0 z%avB8O)r;{&(EEwg+3%c_*qVc!>J5fow(h9#*L-tv7wxRqFxRj9t_xZ{&&POq4V>M zTO#cqCRxs|x8sF;a2znz3g84IvWOseZtc%KzE6xU9+xo&3dO6oE01MQTiEv+Yq0xq zQSB=p$#dW-^9On&p1M+uu;uidVhkd;TY<(-^PIC2pjYj)n#;FhjQ>lTFfxM9^z86ox`b9z4>u+x7}HOO9mn zcnI8^j21YU7$P=wPojE~m;0VJN^E4(dtLERxRFb#H8)?av8j1~)_o}kI)ZzPJ)CA# zY&AGm5QJ?t9sRuy7pQ9_Fl3v2C$kHn=~76UOK$3GH-OM}JA5*pbAON^$L~sQmx|gy zxDsf35u|TO%d%K37vSSZB%Z3LOxC9{$QHaTLK;k{9JpG}3kjTL-!U`0xARSZ_V9m- zbC=sONmz6?fD61GBiJ z7M=Oj0M$oT9qYVM%EE|wb6C}G5cTQYVXy=0hU9Pz@FuS47flDsje?zb6>BrW%BgHN zkly~%y`HOdD6uHBMJ{xgc>Qcpj%_YJ5z`RS`u>C8-!m<*8`eIX2vp8xhCSbx8Qe}w zMC21q4IPGzMoyA`0OxO5Z0y^Sd{Kx$Xk+_U0~i!?PO%NA@R$EYGWP4dt#wNM9{XRG z?E&9^mhC1G$ zis*t+*XM_mP`5cvjJ;DuNocr4mZd{m>Ex}bg+5bOt*fx0^C=#QXehH%Z=4(G2S|*F4++}1^y70wiY)udQMn(oApTIpp9;fyv%mbX3(KiHaB&E` ztcODU1`S~YqpfDGyufDIZce#;SK@FouA7ZSG12+16YAVRVCnRMp#8&cY9fnGF4OCg zgR+cv0F-`D)_Hi0b)`MidFegbly8Fs-K2(9bf5|vQ*;J@%@}vdq)!Hi zNRZkl`7EAl=b8QKR2}^3LFMWWk>#Cui<7uQD#4R>@cj`F=6 z?%3Kek`L265CAuHa+S&It+JBy?=T|=Z;$?2Q7IBS|906XciD18r{OxFJu*Jr{p3?# zD)shomeX{GL)1YNVuZNK!!aBJS(W=SykBl_-Yzo!Is2{!s82_fI`}3ViYISVbt!;KE_96yGO8P!iRO4B#~H)dlY50 zS*0mctMaGfK}f?uHJ&`D4C&()8R2VHpyyQq-@U8fH!3nyQ1p5C&Y}896`A^Tenyu( zkxEliQu2J60l_v`m#}X0N9Vx!i_gObU*{ol;{_ifL?8l{36#WyDQ!f$5d;T`rJz(> zrLtDXq3CY*tb>oUip!#-{c=e{rE7BREI)qqw6r}jpRxQ>+1wVv4twnY#Il;L02~yI7pn5|>eJhF*);2>smtR^X>U{OBL{FJ1DUya%zc*i zd9GGjE$5^0!AC|KN_1JK=cRjbQPN6u_Ogdjw82&DJH(jjCF;*Vgi+ODZ7S_^(;{~k z;nGe$0;?Ma(Og=I?#1PN>7Y~?fmJ2?98ta_D6=C2{rQ)rpFS~kD|Cn`wFy$KY#21% zyXPZmi{@)bmoeiYUKc-fh5F@l0L`Xl-DnFlgAX&*eyh#^;!1 z*7N9Jdl=S23caTq@8HSt?L8($BDU*WNJna3kk+~Qn!v`!X{+$8=R@8XSL94$aKvUd z$E2s-Ax!bm{4N|e?*xy}m!l1z51+4bo#INA=MN#{1oA0V`eB(D`I{#G53?kz3T#O= zx}}!9p~+Uhw>mzy&&+WKLXGdoUb;oK7pT9Uc{g3KZ|L( z^gcgubr1Q1=^7-J7w?lmUQ5Rx9GGP!KRp6r>w}Q|I^=%x87=uVH0Pu)fgKmxLIHWu z3bvG?3$TRPn6c2HB+B-C9woL6?e z0We`%)MK-7oN8C)E?Ja-cn4aLm$nhbfh-Qn?+Euo%z@dZE2lb&jEdI$mz+b=&l!1e|RTJ1D58Iq_S66 zshuY&l9-K+4f7*@s+t;K#)MCdp$;y7LqZvSc|0z8yfzh@bMDCv;|7_;nXl|H!v6EX zbT0q~s{ab`a~^r3P)-?^aj zfMEP=AAx|$*GzuE?XVuUOErHiDqQ^a^5RySrkzrX1hG^+EsP6#fzVaG%ZOh_i(IXX z>4WTxS*)jD!zbv=6NbbykJz`cIW5`M_QRz?omGjqzEA9x*;>vGQSSPiF91jXJ6mCb zoR@IsLF9CT`)qLay5P2qM-SGnqUvt~3$+>VhReUV%6JK(55ymSHhaJzG*@!!nAK?R z)m(JTWo4(Pva%(2PL_@WL4Vl99cC5u1`X2cUpr8_>viN+BySDs4d_@KnH z4p_ZAMS{Jm93O4gZqzn1rUY*f1cqZ>;Otbw>SEa z72|#uBgm#-kI^zdECuB;m9?PvpR{@wx)oH zf3H;xtf!h5DCFkLQ-r6*w5wL1_aPs2ea&BI5oD;zRdqfbrccKV8CmTfS#7R4vTsS@ zf2C&q^h}vAlcn}fO9lPpi!61)1NPx{XHV3Pg0)Uw%gPgdbpZ38EO7j76sw39)}`?c z?tzQ26MLfs(`mIJ-SkwG$>7aAj5dvDYg%_1nTtzo<`Y#62jxI(kw#@U4*a?4rFp`d zS>g5GkX$R@d*9V@`8EA&>PlY_B11IU_>D?p@_O5q*S7BG%G8FRP_S~LFI$C(I*1T~ zan*-@$6})B!rPkl=se>@-ucP<3{&|K5p!83e^B%Hukfzt&V-xEvC&VM79E0Y4t6=y zX0}wPhcJvP3!o|IX-#iw)pj5w4x@FxErE4t((Wtz>*mY;Y{_fZ>xEix2K&O_@?*(t zYITSO`q^90G~}y;=5wsVDzTsD*A(pj(2o!7MAPohV;gxlQ{$Dd!!#SJ3BKRDUAc_6 z^P4Y?Ht&}%UpACd+KyvMv~xFtUfNCTCN8h%B2PdDWq7%1nWO4+9c1+!zLPl;V7_(L z-6Bh;?NNN^rv3qJD+%=P!qTzB0;rJ7DTkG<`sJg|x7WX*Y<5uI`_~F6i%7cE7f#k8s2mV%oO>!&At4Yug76$w}`3Av_26odY0AB zzG0tzh2^mtSoH^fetx{I`{sU{?8umPM(^q?WDo%yq{Nfa{#40Klq~+OP*M%@SAHq2%Qzyr8hy)M{ zQgEM%&QRx5-E5w!Q$1P;KV-N-ICO#2h9|u?=lJ#1uJa_mmf_ospT8ogsql|wLwy=f zvA#au_+oBP6rM01)@o~ieJ9^2|BzQ-Z*{6lkn%3|?$~^Mc5{Oeh4U(u{0MYA8BK&M z4B^*kY1x49KRmzN@OT_ed?jec((|05)%$FArR!dQJX*a{TPo@L9Q}AdqECxM_KM_@ z*%m1_dym2m`Ok8-Wsiwpb5LHc;$?3LV+jTR@i~N}d(HdwVB;*fiI7svX8f`hy{oGA z1?t1O4y0eGg2bI(*9N%07v3MQBTjopY}V`Sbs>A!32^q zTBJlXS83G_(i*86h&z?;3#BTk*BQ)>Alu1_Nt&xb=sI;5u8XquzRM^T{FoV%bl4Os zCgj^3g=|@*>~VT;BJ~!7ex&2PVfrZuy9RCM zg<`A!?t{vL*&kOX71gt$XaY7~JL@B37!$jkX4yrF^fN?c3Er_R_t94{LgoW|NHTqI zXa}dmt@oEZ(g12!UF)qz8LQ@jN;`}1tA39h#Ky3vttxi%2GB|D2@nMAdfq^Ys{I$| zD!=69&Ss-m+5-w$B!+3qYY+Miue)POfCq&6+T9{A6e8}=Znt9avo6x5J1&ynv`RSe z*o^%N?5bT)nGgQ8wG5n0c9j9gO6Sri;k%Kr$!mkZLhr=4RKL~?FZk?ch4Ub~lj<-~ z=6^I-B5y^V)bT$Q>RE2Ki@f*BoFQo3^H^I|E4_bv`y!QC9J& z@=aE9I~>*rbeys1%7r2Nz3(D?M0f*`0IE*}+=PDTbdfz&rRCXtxh*fRENaX~DeJFv z$k|NGs~|45T8-9DZ%-FY0?Z#7tooLUrh`ycQXha5>||g-26MPp3iMTTNzb%ouN9Zj zV5_rZvD0^EESZmze>=Sai5Wq`jmc!Zx)Icqx5$16>SB0#4e0MQm)cbxMEClR^>vSN zI^d{m*Dlz*LAyAqY*9KI*mPfF@X({iOmC}8?PXefSfY3XVIet*R>T_|jf*1pHX7e& zq#>@;$N_B(0{E7IbWCs4`H)02Cz@v8SL&jcIs}DIe#mzlau^rO`lT-u$ffQ2@QP!j z{+4~LsHs}YVf+W34!Qiu0-w{eGD@NKq|)xznlYFgbyGL4Dd=CY}T}>NC5oKoBXz64v0WX zCKNpdu!G#nZMHsZDLP32WvUj)lH9(7-gyJu1ML#BB^_9ND?TsmnZ?2!pJKQ4#&K z!%%Nu6pG|qVKVk+>$UCDGQsxT;{IB5J!J z3K4b+Qn`~8d18}E`aFmYM4@ZwZr&^1JM_nr zs}PSMM+r@wT7OPOm4$S6F}H2@pi&p_qqTa;$M@0bar(mRWciTmH_U^w)_fJ(RMYnV zUMeBD%|0A4$#WH31e;y^Vxz=RyqCD!1@#By8RR<}uN`f68@226Quej?goLA3j-;GN zm9nY<4-W{s;kwPuFo~$Kb@{R;X!N|5xIa;nVc3zaL1zK4?H`j|WFaE1e%D|x;>ZEr zlr*$8VcPY-a{{!8;oHFidIjBP^Cdv#Jm98z49$jZ1|v=&x20;7P^Lc)}R?ndQ$D84nM!JN71wd?4&Xk8Krs*Xmd?wu&GtjPMzR( zv53w+-|WGkb5U;J{?#}%Ksi14oF3Sv<%X~oLh;?&*P{M)4kUJfmqylkRu>D*__9kS z*%tohYZ7o;ZZ^vUT;qd+4W*Diyo@^RF4?xwY10r{#ezf-cwTpM(Gyw^j$^AH3M>#1 z9mEw#jsI{Ou%HI_BtY>oDX}^u#DIecpeK#D6qMJZI&ku z1n;))-m^MY69X4Tt?m>e0_-sPnrdjIu2Gh`qca|xQV;>L3*&e^n${n6_4UfVE22u8 z(5Sq#(_+_ueS0CdDgN9cIbD*Df_1<`q`)#m{S^HLs@8lz0E0%Bst5w05|jzZQfHbI z0}j>`H*1*>9*i!25o;8-*IF8LTUU{yJgjpph0AgMczY{V!OQ$|O-PPLm<$CP&2A3KJg)!*sOaKhp#OQ1KE1wmcc=tGvk0;FmW(&v5Sb0jiD&YE*N3$|f1aFSbTpDD7+(QzgbunNon9%+6$;I& z+iEgEcLg-lw~X7eARiQkRt{%rGZ#~i7|ZwsrdqSgX^5X>;urXC?bHqPvZel$l210J zr|0{8-K5R|zZPRv3^{c@=r+0Dk1-G5lBPUC`CQOvQ$8bKo!m`TAN#qhd!$XqYNG@A zJxNM@cR5ndUBRbfdq9_0#&Z#V`oP47?>3%(5UN-xq2M-?;i ztZ)&JY}y&oek8}aL0396O!<+Q%>~8YvIQ4^nmn($?r3E`K(Xln8L#SWbIM=`FfaQZ z=b?X8>K?8@>LW?f|9E&T(IqZCx#6n0(yeRc4m4)oSJ-C8>Y;~I=jOwy)KgAsm@mH3 zk#ntm(4T)cjB8(t*K-x=dR%C9w6FX~==C~-*yUPk{p)UMYo-QdtJ;Da7MH`me^F|a zVEL%)ei!Z%re$DAs^`YAXdO7dd#Mn5$kkkN$dFG^+)_K*sQ~?TAqqpCt zObx1PZk7QNY}?Y1k%NsyyoUbP3VU1R2Y7AY6-f$#b+^;4Z`BFWKF%@X`^38m{7lz1 zx;*Kb1I=}fwQ1JheGD&(nWkeoZ|~7@a%{F4y_2W?wdv{Njw|B}mG)V6ZIcWa5IAM(h*V|= zs8h%jP5l8#no_SvWgR{BI+-n~EH9TBkt?p+s${%fAIE0e zAQ~{#W?@x|)~rJv%;5G6)OCfUw+rtO)u*~~nj1~y@CrJkzJ9TPlCn?K{0P2s9 zTzCW&A9Y?8&{?hG%>zyxAnm7aaqUb+*Tvf1c8`mWh` z8}pk@7}X~6S-|4w8RhsW9%L$h4Xol%Azl|Xp|e+Ku6B4NFC=psjv!>Hqta=%FMk|7 zb(+=-X%!s)c%{td>?(oU<`~6v<=Pg9y1Y`z`pfMW_TYxD(Hv~wD>>m$u^!VkQRla# z%p3G?r?!oO_*Ru0%GZhQddGK59$I%R@)6t|97zEbvOu;z@%8>T+!G;nxL8;>5_8oL zE~hjxfBxNql-Bre{A=o&jO6x?57nm*HI0z`tuA6;!{^z)*oMw~4kINiWi75J_qWcj zs3=1T0TF9?P1|UUC%4_Y#9RHY2Nl6Csh|8_UE*Jo0X>r4_zvrCLux7GU6lf-VP|@Q zzdsCV&yI{bh^ctKX8l2;c7hU1jvljIJ1wdC`hkwsOlI*FhAJ)(2#xPhWGi>~jGnwn zB`Qmw^~1FNQ;+2$^GSR=O@WqXOd+-Em^k`#&-`sr+w(`Ww^wu*CDG=5d=`(&8IhZP zA5~w#ZaaO~HH6zaC0k%$X#Ai=iM&PO>fLz@RnzW6;w|upS=_X*usNt7kKK~*A^+&m zS(4aJV{gJQx6t@($`pG{sCZdn%(U6HyqP^)Wla3C+Q8YJdv$BRcT#M>H#y`K9?mQv z$c53JUTrT!v3GEUSE=kO^kHhG;qoYLl%OBF9N_z}N)QW%1Pb*ByngHqwefi*qD4U5 zQu9KEW?gE%5v!tlZXsyCOIVBQtuL?I?*Ni+$~CmP>#DlX>INDP z;sK-H9*1ZQu5FH!LeF-;So*`l(X51KobFpOoKOCTyL-Z>M=PNR-O-C_o76AP&l+w1J0vgv~bQ)nLL}pdLHB!V{zjp-(K< zA{C_>wZK=ThvR;;Cc2=xdj&U^kXGfG*) zls>A=);ZNB@LeIcCCqz3cH-7G;x*>aEv*JOw)%9_s3wqAneilhP)q~wi)lHy_eSRh zdRNIekYXh|v*R=hNbuzAdO3lnOUPR#vZL;_TEEknvQHbr*5Bm(Urr#v;Zu>QpdZ+N z3?%czoCvEm(u1!Vc0Ub-L*=TxrMR_YkubJ`hg-47JO=&Tvl~PLSMeaALGSP2!=Hs4 z&Ur6Dv!F&)=uM{_=qL$8{MbjcKEYymZMO;Q&LQXhpicap0o^v{t(o%n9M*(<2S93_ z8U@Ku8-6BCsT>;xUenn*$m__)1OGUH7+M4cHj%}(6C|+ahI;_hSLAKZ9%A8jfNAiB zocu8~>V6!Pv#3{7OF)E#X>3kB*rUG@j97VsbFX)6U=6y>r;zhWbpUyJ1J4Wi%XC-* z_Yravr3gQSDUUP=Zb%@HcSXaRa*t&Lmd+>p)~ECedc*Ww<;oz8D2%u+f=J@GJTJcg z4RetDPATdT7;(#UlHXe_Cq#P#2dj+FujLIQ@SfP_;CGb;RYsJe?l#gM+cz zTf3H9$TQAVmE0x6g`NV7%n{EdWl-KNpt7)$C(85^;+h&@pDlp8)t9Nw4(1Jt9(XtB zMycXL{f%W$2=3mTEc%z{ZYn+*8>_w!f|OD7+|*sGP!A1lK;+oyYuFuy;(8_ji_~V_ zZErQr@to2NZ_cnlkNmepS7JM+(*=+0;F$A_uHdV=l=mF3x0M0>^R}^gC_yOw*LnWq zwa*>fS2mA_59Keqc?ALvO*N=xF`)qHRFPQWr_sg|xhncGNqV9Z^E3>3AA8XetGMyU0Pv@z>>bfX^X}8Rf zd&L_>^1yuzTqO7=Y~Id2p>u9#c}eW|0A&*SQ+Jh`t0TY_j|2HX%eKpQJIZ&m5UVBHkp6{zJ~a~|CSV(!zbKghn=fNG7k&So7eRG0yRIATj#wuM zi*Eopc);dEX16d*C|L6_cF+=pFWbiSU;k;f6_)DHVRwLwds0?8Yf7?)7{CFC1YLL= zm7i{R+dTd53@`%-n+2=ij>DF;Yl_fPgcZzw&Ybityk#G4l=zu}@V;ug(mVvtnPryr!CE0cm z+Vu*+Vgc;{#1)nh<{Pf7vj!}LP3KFJpL3lN1Fu*XZS6iVM(_krNQwZU3G~QGP|9e< z@yW(Uj(Y7a>#)B;Xoevi;VF0Aq4s-xxYTrjM=$j5?~!@Z`+Cqz!+8-S@S2}kSUI&h zrZLp^$N8O6ZQUsS|B!XoL2X9;mk;h*q&USX)^rp~c-bcxfr_P@q_`Qrv?F zm*DOW!Gb#kHhp(?cHiI5{VRVZljoT`_nz-LpK}@hZrs9OI}6FRI)ed>bARP<_pDA#)%X1ICUCv(t^=ie_2OJMGiCZ_=g@Px2TjREyuu&I^*A~YY#9LcsT?<^ zcm-*+`1v^7KSVKp-}(8Fea5^OCElif{=f?+Tq~~j>iCYM&rzGXsO|XM>pME?vlwg1 z$&I+Gkg`A%OKXwjdY{&MRoS7cEen#Bx~@$q*g?Vex0XbVr_%#CX56k1|k}V+a*64tfQBi4p82SXG$jdN$}9HxhUtYfcZbA>=skl?83xu z#l}Ka9J5(naKVP*A}cPSwcvwl%k;x7D;vqmPw+(zVon=h)}S`0s2<=6{zj z=Z#%shz)Br%6Y?R?FK2GUiHRCgNBa<@rD@n4S4BtcvN~~e!W59LOvV^?%rH}J9jov z4E5wHEjUV)_hKU0e2Hh9a3#vP)Z@PENcqDv%2&KhRw=vCveS~!UG&lhb_PTh^2f-W zck4)zOb_5oNAdjdw9Zgxc)$YfsV&~v%M7|`!B}xOy=^u6)v?VY{_g$BOX0;a75&R2 zG@6kb6O;5nE*|kp+ch86)+rG@(|QbxI1A=))$ypEnmh9^>)!9H6MRsckFd9c{KPNM z(SOi-FQ!(UU+z;vQeMf%3a_~g3Is*#yj;c@29yLf{>%n;qn8WY_!)P=Ebn54a+;EVpxWDOK26r77co_rBc z2RwRvQ)&tynt{}4M8$5atR|YxcGnJLd#5c&pcIV!5}pFn?@pN64yLy?A$NuHvmeHy zwG%_+&UH4s`cILiHW?l%8B}&nzJ0^W9j`Q(wMZDG{K4$*2Z%-n_2CIZG28{RkY zZV2_hT?yIKK}ZhK*YvQG$aUJGV_A*vp*P1X#Sb-o6BozGNkr}GiOI9rMnROh92q4% zmWivggqAkoVj_9w7oM}ExqQKbxz^vn=A(ptk)!}3dt-ob@H=GRs#KKU)e@gw1GLD- zL7GoPI6MO@mn^!hXlTeg$ituL_Jmx2%a9ef!8q+Xb%+Ms=}y%WMh-GSAjdvGQu`H_ z1BOl=o?e=~05qsY_b;TH_u(c+GnFQ722j4|R3q&;FY@i0r^y{k0v*OZZNE*F_L{L^ z-QbLTQtw=V+&!j;#@wnMB>Q*okoF>=Zfh~%pw1SZdu~6vi+Td(MyT=^-*)AYCSd)| z@c_mpote`>3HgreC{V3ec7vc4I*PV9i18OG>r#LDz?{hc$=|ZZ3Eo3cR{T|-TxW0k zTSIqZ`u(TCDs=q2@6LO@XktSIAaO}<$mdCb+iwsiW|X{0!0c_xIt5td6`%!BX7%~! zY)3p!ZBAYrQtJk*heM)0uq$yuD!iLX`UwPVosmmpPVDvqrZ(irvpPb0dP8qQ!;O8uSc$+KgySz6n-(+YJDftxWB_+F<=_{i!JaO|P+aA(;+gJ050gS~ z$aD=i_Iza+Ka>B%)%Y{^jR7HKxq?6wl*KdR8MW?Q-@eAMxN?Wp=G|JLF0-zG8_!IPT=O!NdlJ!AM1$pY#Rof|^>omialerc}dB|zzL`i${ zA9s9UC^wD;;(yP|SG?4c=^!B*KUG47X?0otf8+1lpDy(ERIMna4X_fgoX?rBF}tn~ zHQA6X5)2!!18%y~I<`&xH#m+BO`pF%JO`cz00rE7-U!Me8x0<;ct7tEtfX~ZqTL|s z8al;qn#K-ryWDFq=?=~vd6tl1U4`D1}vE5)gri zWiklMN1O|=bSmD(qJ^Gf87zn~_=}ln1Q>6bQnqoJGBGMJVjP>}GlhAA8u~^AOk}eI z?`?H|^Th)%xjh2Vp2QzdyN?HVAS0B-Z=hOT-4Os%Btl}AaELWS27CeOc`nNLKA^;pG{siKT-_g); ze*}c&kEwie*d3-2fG0VB3sx|SF@FV71?WnF5pr^KVgfVzdor?X*C;ZsRAMl36Zf(G zy58iZ7MN>x1`rmUXw}8=MI$w1I_+vODC}F)`zGPlYRB*cjZI}pUq;JecAMW}88mza zfvsO2Nc^P3ZQHy<4w{^Nd+eU`96Ec~Ih59l*5`e~4lYj%sQOv?=hQmRJL%A2xf)?D z)VcKV-s)2&WD^@lJwyO4y&*aNLnB!aKX%kaj=4-8e{yh86$3%8v>34=5^s#MNMJogjq#=za($&pvwr&-GMH+ zpK|uu_hOe4a}|-47ySH)Dyn-okiclQPko>GqY8Xd6@I#ANB%lq?9{M?p0L zIZoJLc?L>0Y`UKMM-2&o3L_Y~ilit91vUTA8-!0nP?{TxlpveFO^v+HwN+SL*3Wvt zX+wgf?q;^kY1p7;Zl9VUEp~kI30n7r`v?0a_7A)P?9(M)bv(}2LuNUNeD`vS%3tPj z3MgC9OWWfGwZO@%wDI(|q^5Zt%CIr=>6;widy1z0Sw1Ym{y(Ozx07>a1chncwJ%6n zabI40(*0=#f~w8?25=@wE-GA1tc}dMVh-;j>_n3V)HPm;dbLt<&~{QCxETe%g9)o_ zwdhq$pJ9X3_uO}fiPSJyd@(_>U0CZ9t<0m-wwj(MAfpX?o*%lXQb%nM*NZS=^PMg~CX}3oi@XOz#z1czkUVCceRpx33h}uX{68 zj&BDwo%)a4oSyT#D|X$=TYkd@b=C{oDy{@m6z*RtZ?Tw%*H1}som`YfNxqg@GR|=X z&3f-4Iyq#G+IvwX`dF_7mm8N9yfs@Pi<*4dQ~6~I_5|pF6;isAd3L&q*}OO?(z28G zS{+aYIIV$h9 zrWqsvO%-e$ko-g@iD(O5mw=b3373VN1Z{aj8ns#EqBqRJNWd&DaZQ=M*_2&UeuQ3$ zk%lt3uj$TAKb1aZy^Nq@bLP5cKMd)%JJ@5T zOkHlZ%7-JVT!t&H3cF2}LGZ((A98>By-mGntNw);r%IZyTZYUceq2NP4yU8s z{NFVka?W>!sAZSJjXpa=+D=c83d`i4CW1}}wsGCa;YffHJH36OLy(bY;Qf9vuA&uL z!H8*q=QsUMTuikT2*xP9VC=>tB(LE?nCy+pUYiqDtlIfJ6qHyNbDqV9oLA%HGmnznU{` ze9YsotA@s@0dzcVRlV#IO7HU^q2I-Mgao;km_fc-XUKXX@e1 z`)^;wqIIPY#^1gN13xD&MAb&ib#{H4HH6pcJX8J+QC9{@VB=%^!bR%YNy?gF5Z^5A zrw2lkQ%n0BMP%32p*(WAAMS0+d)I{{U3{lf+oTWp0977%0-z% z*m%UOK4a}aSKVjavptu+_*0~p@8zW*IPCcj3Zc$?JHHV9vyIu5ohemsUv}b3=@S_bK&5Z=cv3=iP+Mj)wW) zD){Asv`qr#cKiqx?S6*H3LiJ}}HL%khKAfvR}!N}TM;F4dD6EKn(z!fehgBtInu6mWfrDN9Dan8suJ z77)MoOC`2fI9N!m_ezAGk>18HSFFqshjeaMW`&-1wtpInFq^L(k(uqSKZtJe3zn7= z+57#3Nltz?gU6(i#J&dI(v&sBC5DV zPnb#I7*_u-AiA9)-%nqjzzv6-%fr6T8hi+Fj3yO)7X|U66}MLGX1zstVfMZWjPiv` zAg}W}+QBtF>FGwB-U;3gPu)A>&hh()JlDPL%Mcc zG<2VLj|!6)<@-LEpO-grfUTNrAE5n6PH{dxZibzO2@y`qK39(qRybN>DOsy2mMclT z&dbRKAlbl-3-8+pKvvo3@b{N&?j+bk#Ng2aa#LH@K4wdw?@|f3MFKmIF1J3~0a1&& z4$9)WJBhm-2e@nZ11TZ_-|TIeBzI}|O41D7A!;7H0*^xHCgDFdeMWDODlWyfo^i_>UC1YFo2BieA>1jeHo_ z8H9a8A#FW*bfb)vZ%yibvW(C@{H&|x6By0ivvb?uh z4iG!>x3+3r@(SkD83Q@nW-6U2{U_)1FYEK4yidSzh^Wt8Q}l3YSug3N>l@CBbKu2y z;N^tE%KTgNBY#aJvl?S7S?Zzg1JOH%+=mScrg;|AHO#D}+@{TUN#d3$bRoOhQcywBNE+U59G%{Q8!I zd0g&bqb)XBGHyYWEByT-38h^;6Xw76&t5*t-g`jGA#O5j`)py_CRzHjB$j%Q8sn!k zKXe2CwnhSmMsRN=0A@85+tngqDwJc1W-SBV74S&>>OUlB*wvpE2F$5=eXQBZ`WfVi zXHKID{+k?Zze9-oLnSzPgBI}F53r2$N(=>+K+4CbFLYX!d%E@;$NS14WL1!{HT*LS z8%Zi1@JHT;#1si)h+g`lo~%O;!t0wHS#B9#sDMNdYexFLQBwZZV2c~4V0Y_lSd_(I z!k&gF2d6AqZVt0xab#r0p)1J^xTkx#BZ1*#^^t$7-=qVqTYpwS?Lb1<4WC!)RnB!N z3@iDSy%QeypQQ*~MN`eB5+=gmviRWE8-cA88P+;8q8wVG#^oD6XUAk@sd{|OcY(JX z>AR7@sIrPr;FoW56~Tv0hBvN$%?s8{(m$9o#Nj6BTug{_jAiW-@G!h z^~Z($IC60Qx)W$wc(Nt2W>xQ-B2Ewl=tO8z*Q{AjGyB7~60g=b_!*f3U!>iutA*Ap zL=qpr1UnGG;&er%h(gs2k-l}!y8iiGlUigGA}{ppAN+?T&&b!L+qCe7Ger)YBX8`V zB>hDkPHTc+`BY*z*nko@MQgaea{T_zVK_YOLg(*h;h2g5nTMLJtYZu?C`#UIc62z7 ztGGYcpU~h1#7|-Yxs_n2y7;I_7!{2)`R%F4x(XzfcQxuia;ML!P<+NkmqCI+oVT>6 z=G~f~m2pCUd0JqjMni9q-Pn^reU5V`!9{*m@Sr{oDJSojvoGbe8h39ny0iZX^AzksAR zN#066fdPigN?-QBQcY?Wf6P234OyJ)c;c^BMtOW6Z&1LeE(}bx=h-9aY;0m>%|ZA- zn~9jaS4`nEH1BhULLD3ZkeS?X;C-% zQAM1|YZh>-?x6H3Ni)(`OE{W0S=Rwc2m(KRNGnH zf>oBlr8H$F|3-zG6<-#a$$L`Eh9eoSAe6=IM4a0|IK}|iV{H+qjacbluamY1r!I}3 z4w|h5zNcJpBzuLiP}Dz^lw`=9`ZA~X380ePo_$I9$Z$uIQM@n57P;^;XIwO@_Z0@I z+8HNsV#C*f%OfK6yRTw=7dAHjX}TAKfOTZe$%V9keIMppiT_ap15&*8cPU-SLwfb` zGLNbC9*%Ok!VYgc7x-~>g2?@UA0q$x$#yrTzUEMMSH=c}zZ-^rHda)l$Sz*9_obP% z)PLa;vXa1QVC8H2G^#VQuFC#eR98 z+Xu7nmV6cT)j#hLcm^I3$?6WQMxt2;scoY%E<*v<6>$OO9|I7j<~M>_3geTB*{Nf1 zJq)W{LPSeygiDj%xjHT%FGLvK<2h}{GJvD6MCe{r(dy=fL|hqwoEXn|S80s?8Nv1`_g@5xLdpO`)w!kr$Mit!N-cuN~>9ctb%Sduceyq}lMnmHSggnU;&(Suw(jv*)G{i*rT@Yi?FlqzftJ zDlw7xrkn0*oRd=6J@sNZjz-cc_nvP|%)Ekg&GaI0vdvONZSxA=jdXu3*nWoB?|bgN zcci|&CsF^%ezQ~Q-wVHFmHhN9@_h}t?XZFR+l?9xV_^bH;}FvB)6&V^HlYqtg&}nQ ze6+$?6ff6uwV}E=v-47ju)VfdsiVIcA;K1A zd9=6qj!D^nzs{v5OOA6!CU%Jae8N|-9~n&bRDFh(XCV3rY{?Gg<$G)9$N0QALAcN( z=h4(~=gy4Pq#S+a7W(=~6`pF2zd6HkQ6Dr!eg!D{SugSsrWDknc-(cI5SO1bIA>%sT!Il9HJPLvyf(zE1;uGnGoILxL$vha9F>f4mQ& z%^dVxPpjv;KMU1-^6fw*)6|RDG+-fM-T^7X-0$YAS z)9(C!1FqANIm0Ru_n*D{|GM^Xh1_!?oz6cgR;hf(lua(AH0s|sVfMbhI;bzLP$W|Z zt;<0uLavoU##C!|n>B!gF%#m_V z%dQszhQF=!v&ljIw7}_d!^V%+Q6>r6mmhCtLerM#t1T-YPhW|u)k(>0KZ#ghfjd!- zM+8j-gP#zrM{i9QHLn+aaqe^#aCIj&9?(dp0Lam>aWDpomK7k>=jwH<)vI579Z+iq zc_Hb9*|Sy)Oyg|5SeC6}sf^#bmDm5QmMNe;yS0J_)&)5(HT*Rh@nYFp;IsD7fdW~^ zX<5CG#67KS2%2hOGqo+5%;12&%l+e^r?KY^d}<-H)}QZe6T!!>Zr`#_D*l4g`HIq0 z?hkHOU(5%LsA@h&x#cZX#EZtLo}JTf2jBaDuFO7$m`U@}DSCFTmOO)(4W;BdSh}U~Cq+%bIMFhA5rOd42@ol@aKJGl| z*d)e695II4QffpET>MtsM;!}riMqY1Cc0p|?;!IKw>5t>@=@hOE~~+Ul}Q-^$H3yE zo_MueC%y>rJ^DMC^<=MF2@W({*Dg-0u(tbCD}cIQJdyT(EqJXYRI{Gh=|K1O`-alk zK1gZ<4CpX7saX31mYV!SjdBuQstHEybfu*7*C{ow*ubTVtLbt{MR%_;!XMWd-__sb zN$F3yv*59B_U%LYZT?b`k-2_Y-F{tt>)g4w-}1C4)E@FlT)FUQU)C#Yh}%T|pDo9o z8Z%$ae+@gNF-ah~|JQW2FMGk>k+-h8Z!NDQ?QvqLm}Cah)Kn-J1=n$*_(vnFqQRj# z?!0QxL4w7s>$w^ArPN3Ko0DqiYnuBLV5$wyL;O2l_-ct|K$kQA^Va>Wh}r;i9?~xz zJ63Mz#T(I7UENj{&$5D-9RH<>B3$YwTVNWbj-|g$P)kHV2ZZaV^YDNHxz_i1W&SAL}7`+j#@Sot-LH<9P0Ns*&2}q7uaZP?n-TQ*xx@ zbdtT|)L|nB_BVSD%)&F-{f9%&Hgv27F2YJ}&r`M=JBYXQ=M&=!LW8v6@0f91X_Yqv#!OI; z;*Isy`<(oHsR%QgyP#-pL6dFp(ItcxI?xf0)=_`b3Qy&PoUb6t0e0F?m)(!a zMHt&36`Lw?;XGO#5F8gDk`6`;S`vJwhX>L6c z=)0aAd&kP}quUkV@^L)0ATsQIjw{XGSwaCrqpd|*sXV5~*O0C|M1jI_#^`fh znzW_g1(#>TOT7SS3mVQYgvKYkJLaw@;ssNwgI9p(@eKm>x@?BDWUVEU`(IIqxQ*0 z%_hu}dwQ@rbd6kXQ^LUr8BHCwQW#_S{AN6}(#$4#tXmHXR5K^_<$pQ6T&hsPm zc)7{_cU*glxzpuZ;DaNT?gcq#Jn{Po(ZD0nD3#-R*EO(+B_ST6^T(mk)z2{2O8E_N z4=Kk@T+Ml}mMTIFyaH%=-EoZ^j4N_H`ON!G>F_WN8b=jm6>6rvu)Y*w!e1xI0Q*0p z$vfK;lDZvPe5C08F2?KBaFO3uGoQb7F*;kGb-tPZ&-je-4J9kfkv7?{-w&}R(cl-% zLWO3J@%zo$|K}4$=nKcMZ}Cv>FOMCqb<@()T5=vQi;?%;jBbv_M|kh}a_*uJd35&> z$Tp%}qxDt)3qhxw)i(6)S8|4Bh+$4t6qyKbc(7Th=bMI9HZV_^!P`1>NjTOqI1lAaQ$Q zu3719_TCb&DlES+$Q^7Ph8}vCbs>PlPC94f;g-JHoZCpfNb7AWcW5`WhR&}|BEToE zP7P8|l={^fgLWvUhPbRcZhQ9N{hjcg{-7-z~K)&AWD|o`E;e-vLP~f zKb(}5bXH+Mi0n7veW2}uA{0Ilf*;Leb^3<7r8P3pSJ4vKkF89a;5rj>Z{5=Y4Ki~@ zONhARk1;{Hc5qZPuZcT?Zr6db+UiEziJQO%33=f0=gHgDyF|&$);5rE= zEvc^g{xy&M?}W;~PagQo#;2mHf4o$oYKY`Hvxnd*xxFQ_)3_yRzFJ|nuD139zsx(- z24Cd1>Oi!;diRcz&4uElVN<{*;-sr4HAc2bz|~6%NvWBwG|Q zr54=2*d5hg+&I2kd+f_flyB)|_`5_Z92UqM6%S9k)?aNLWZ*t4GfZ%;ory3aXzYmtEo_HobiWWS5p^u+k% z-Vk9-CuCffR8)9zAZ9vY%eXjq&yC9S{5&Q10iT8l>}Oj~O!a*cnW~fgq4yey3#2&y zwhc`BZK={BY9yPZzHsgLs%)clo#pM^GwL^T#PV11P*Ls zm++=DmrF!L>@|;SOuZina_e*~XNbl)JVnq8OG91NgOHyqOq~@!n>87gkR%xS2~9msiWUbdanZw;V`eE2wOT%e3y61?e|+TMN}gA&_#us>nU%bP28ZX zn6L)nnfcI@gx+v${XcpENFKlEj$U+YT?J>=W99u@V8WTxwv-|Dn;aqn3s4!r z`mh@VX}tzwS&%v)|wmL^(3RzuvIkEv1EC>a8Hp+#V!J zot>GtEnTj#iW@t{3i7yl~=@+IS z4+M9&fSB+?l}giy{|y+83UBrnx<_}>tF~zb6+A2dwyzIC;+pR+cAJWG{1(gn*$JMA z4h}1u5K~P|2h)>mpG~C{@j)BpVM*7`Fsyy{;>_R>G#qlw%j``zX1NpgsLLe8ai9te zwOHttyurdSfJl|~Tc|r*NAt2=ZrEbGO%WVVC4BjJPuP2h;pcI3+^5v^=ls#v*H|bA zHFSy(nf_!VKODH17jASnk$+qx#-E&;n$iEA&sum^M%uiJLm{vH4Hn%%pks617E$Cd z)u1p<;itkYm>0^>mof-q&VP1@5w)Q}=y0DX#jRGiUTukB5jnvY35b(#DNeiw4l2y` zzT;69<;%P`$b`*TGct@<9HcOR68(p9ssb%x_lB~zRHl6hZ zUm0TWy9eH1aaoeRSb1Pu(72e1 z?B&0`M9n=orGmp-=ElQPRN6=&+oEMIg429@Af$|XJUiX-LbY3b`nje}(spek&u+Oc z`>o7>3BCwh!B<4a1~ssjc}4*U{r>&E{yS6e{P(HNV*yXXwH3(fFC_y*&l;cX+GKB| zQx>2h4qfOCD>VFnX`uHd5c zaM=%OspaO#wcn#bV07~4MAU5En8;p zqw-QuMupUQe*!{PKoG7HtdHyQEqG~i@Zm@7>E2vrWvj1|lFy}$*H;f}g@vEI7sMJR z^b^JExJ2mR6rVJb1PI&#SQz2J-Yn5Bueu3=<`w?e5Rm9SH zvb)PNGX?C*4fCM&tm_H+8d>=Ars_8Y1w!hpK(zFSBhuPeBmR)Z%=swn%xSGXK*y}p3sqC5riW+FDoZ}~I;DCSzJI#;h9VaxoAN?S1T^aY==bC5eR1Nx#Dd;gksLN;> zt)eks%Z(#@l1^yn%`?HY`^M>*U7~)*EV{>PPOTqZRsFfF!%y3Nl%27ooMb~{D3=j& zwscnUp=r)~t9tm^ceGmaNSE=J21JcGdmnS*hf&<<{88RpTv49X$^csY?ckCquybG1 zb)0-9Vd=0|lZ?uNBDyrps?sd#diXI_jpoGSsr>fyp`yJl{OvBGbT zd`%~|c?~U#!^fs3KnwCHqAhoLQ`f*Yw(9b4cm40R4mL*aVE>403#$^2@`J`^)mXj$ zCov_V2Qnu2^K+yQr=(~j4^+04BfDA;@>0oK2iqCN(+X=GU!O?Qe{MGtrUVr`h%zOA zSPM8X@D;!eHm%;|e_>q-VvED}-b$OoOzkFu?+%1{5{*Y@Fo)q=PAfX>kicU1J zYZ9PyLJDeAt3z7c5@}Pi_A=jzDb?s)aJtwn|C?m==P(d)h8t$yX3~#@4rTaH?Q$Jo zQiL%4)vP#BVjo8x2sqznhhT6tQYk+y9(H`X10|4*;f7VZNx~N(sjQY={fC=$zAjHU z3+~Y6QVtVO@l}0W+X}%UJm>ZFw&~vTx}Tmo=zbP{Yxo_+H#XMBR(&9~Qp&+tYMVi% zT^^aAV~>^FrrF9P>@dM`!VN^%8TCk8lRgd@Pu%r!ZJ(Khy*C8 zgT|6*6Q}@g{1{%SweS?ZW<|5{wkstir5Qz}9f7Bze4Q?Y7jh5GFq~PkIk`Q`O;Nid z-7&D<)?B!dN+B?+mpM7j*{&hr+H`DhtviJs_BFG&*M@zUTB{12bTuJ}=l3;5`qA+? zQ~ALcNhNTM`Rvo2Y&f2)8mIAQEVan?L4CXZoi1U{1`h0FOTiUJj=*V?xkr^XLLLbX znReb+OfE&{EioTp)~e(~aFnmyF6h#s*NW`UabV}YYhXyceZS4&hx8Iq@9OlX9_}Q zivPVndjWzcH!6G^0riD5VJx^W%P3BM9=uCQC-8P6>uNo`5fh9Gu+C;ZoM2wCE~$s@ z@3m~`v*h?!!^97XyJ&xX=#f}rSSx#9f|v2d>O74M)7vRECg|9_R;{5ly0sP>U!GFi z-@0JzHZ+V!`It33=9Fr94IK(EdxS{8CmA}g9|L7wGm2f2oCRiT7+sgVP@A0Wf&9<& zXr}9WY{*)mdumfeciSC;xVEx%QugjuKt~|F4hxlOfFJymuhQP5!85C@qvIKV(jqOA zNoj9~IvS=@qt|r><)H9ighwU&*jz+wFp+@Cm6pI2%`m03V zFw>LB=^E!~@AK(2)wxG*F*{!bAYoeX55i#!&eYrVO*;^@Akw7Asdja`zobC)3fLYi z`Zg`Gj6X+mE)o$V7cjEb$!HPY0iG_Z>7L^Dr`_&=q5syi7vjzGWta z5!%9@Dzn+m#0q!)E*);cvyj=)2;k@2Z}`9t9ll8#;rPyw@oGnbkFkJe;R|T4^jD+j zK)A7VqnIJz$1DlhN)ksGc$2{b%S~m~7+`IhS22a#s8t~LC_IH`C2z=fLZ9rbUr|wA(YKh`lyN7h>#AC<(jojXyX&$eX$A&x zp!BjWd%ZZN54DcV{V8WK+rPQ_Wv2>s6Vs~Mu+BDj zb(vJ8an3pKQR<$9BAhk!>(CBaJxG=GE7HJAEFpg67OHCPCgV7OY-fLpH@O3gzYSW& zfY-m+l!w2nE97%1Bv0Mr?0r1}kwS0dUZ2sZv5BWhk}d1)Z#B^B?yitNN0UtHb!@Cj zO&};qAAkaZk3#NTcxvpC&GF6%TWxeD+r6>Ynr-|!3X%!=-)y$0PWMsb8<>eBe3+qR z1^AK9(_W5vQeIe>&wKsNn#JbkzXpz`_FFLl z?5zbne6ug1b;gz{_b-7`*9MzOZ3|ZOxT5O6&(1rO5J_hr3FPh&>u5_0!MGKD_bT$3Tfh|4EK~ z|0dumaWMoe)EsEM-iSPu+@~@jtmuwm*-3t{l44^uhMnc3_L5n5KU(sfz!8~iI!U0o zVq7-o_XoloqLmOgE|J8XC&4!0nXsk$#^2&}ld$f!)~xE`CbKfDPU z4!Ul4N`PNn>g~6Frm2D(vqgv3QFUB>4oYD4MZLQdLkV|YrR0KyRaCJo)n4*WMGU#A zu7&7?PE4fNDZ9JdaUI6Om8yd8!&a@f)l2F^{b|HS#nnVp1Ax`Y1pC|V{zKE*6u$9J zn^*&o;6=zzr|+&I_~e`0Ir7C7&Cg2oYAfF3(|%ee3aK1k{T%k)S5%BV;yPp!Cl=E> zSl!kXt}1fIZD7D*Oe zKp8&}MdjpH-~UIYAi+3(iHHNKRmPMgUY4?-&1x{dT0<1vaK5)=%=l4C9(71O0F(3? zkWgx@u@$zBa->penaMuzt?}tN`(U|2HxI#+QO!x9aAIyO?(B&c`QfC<+TO^^DE(Tk zW8o_EuBx7&lC&2UCo)EzL_LGNC=ecns8lT)%Cb!XKEN7RN~VgVLoX#?(IguvF@XPk zY&U)>y{~jBMzLhdx_PeQ2$L4)Op3NR>xT~`)%vyOa1h$YQSaem`~(xz?dqxwwQ`13 zfR8`d3}wAF|9+@BZ@BuVnd(iw^_U3?E|RB^EXAAfFn~S4hRqmpNz%+c)kj%SR!D0e zbkoOY3nN6Px0xF?K0e)$Z9oTT#gNboyKO6?Sf!gHeG@wIZ9H${Ru>fq3?Xi=5N$0j z&JM*{O3U*oyO zLW-3bPKpvg0`27|r)AI?`g^zIcZb@5cA`_jhs|TZG#ep$6_0t$Jwa_{J@j3yR%8$K zs^uEX(vTp4?JLv`(hj6{$dEFgN4S~=I-t=$4f;*wH6fO?zDXox1E86 zZuEjFQx~eyCa8H|baf!FdEW>3fOhLKCqw8bWS_mf!A;eWEAhqXYl*-|&{YIOJu|d7 z?xlp$)v+xQ`L-%xN#N`_bVoV}YR+s*7y+{$of(1&xm)X46~y85KD3b0wv&=Bv$(ZEZ`~drvbT!nX&*--1D~wT_%jdLFU-ciHKDe>g4?_`U_O z4GPywjH6CDDtNfW=KcY9Zrkc^+E)yMpEXi~6TC$Z(LVe-z_zE<@4T+kA3M-`6!OfU z9?|}CUFfu*A6Q>?r%1rW<&O6;Fv}ENzZ|A=WdM8VjK?zgApl~4U$TPwPq~fncV-Co zv`)M4Yjw%c^zm3;G?;+b(aTDU-}lDaOR&{8mHu;TU42>Ol7k+h4En(Q*%e@ul*?shhvRc2hq8>1$n8cFeNOZiq<3^%uC#zRiu(D>ePyuC)>x z$X8kWWC~I*zfw}(%4qR9QLCE&UH!2Z`UOwqZ_{Y-IJi|#hr)E|YlAe_tF{3tl#>Ux zu<8?Y*yoe=9qh=BXKRbO0|mb#zaPIfDorxt>VwQAp>bOFGs6u<3FHre>qNHs>g&r? zWYZWMDc9+#iN8H9?kGj9v$5cyJqt+^5so1mc@2NmA69CPW0$uLA+{;@L(W4{;;-SM z*Po3(;Xjm0O|5+H%i`+g@W-!dA8wBgPF(px)a}qA9~2ComQ;i1c;-}xH1?HhNa2RG z;bNzshTj#bpYR-MV*^QFcTgX$K?^=C(=(>ZO|AAyqzbFg=jXok-`vK!^7b9Bc_Oo$ zY&y{z9VUI!ja^pfSJ``SO3gs)@|=k4Z-BhWrSgSf@Bz1<^X!T6Ulim2U0|3yJx{S= zhh!_J-gQIYPric?cohJ@Y z9!655k z4kDm+jN#ZHnpi$-ehoWmE+ycJd1awQL)&{2M~bocqKqp{t5T{8^GChIf`%?nX%B(K zEf_Z6)E)K{5ts5nz_(uRy_3%+1&rl=#Te=3(di5Rfyp}hOJd6pdzz~9!VPJ1uEN+} zY7wFSqtn8O;<2i*PSNN+3_?2zR)f~Uasa6Wl44U}UI0HQON6&fE(u^wwr035k_>?B zLKvTTi6|w1_j!D8A|FpnjI9}fh7_yf>0Ex$=}G}exY!+WFDxuXf5S+Prz4z(hMnPA zKVNMcOj|KVYD`aFhCmBRAoa4$C&vRkx;C6ccMIaiVawy%(uBTjB6{h$r}mM|M1>u82|Y)0z>DFalC({E3%MqRg_cFwor{yi=!L8GX^%XA51xk;8wQ7OHHvB0nQW7?8Z zpUg)x_{qZga;d1O%7Ql0v(JSLX_;dXX()pwSyIrr{M>towb0>) zYR~f?C6xDR+{Sjn7w@mqyOB$fCMitGiMuRrQCGUZg=r6?(n`5KhOiPg*z~x~tKdQWvuYstU+n{csuUmkf;!XR@Ew&WEFk`UgFJ4vv zt@CnKr#8-|R37S^$EsU8n=cL06I)4$C{^WGA0H_=F}StB0)!P(oof9n7Ze)*^KGw@ ztax8sju|!y+Y6G&F@iBaJ)LtDRbhbc<@Di1Zxn0+eWF@ZnV#)KveE)_FLl^pG{)Wz zrMmygsyIuoHFXkgcG8W@S!K<6>uwC?*3Kkz+>+7zmN!m55=wW}qF&Qd_{pjOcXiHr z4ub(Y-Mvd&)O9NDIk=tsJyx!S^4o0!L_6e!LN7(JMB~Q*U|fZphjaCr&lT`w;nDl# zSTp((fv8(=hXRJw#NS=h&G^U-+EnefPZU}@fs)JL+u~W$mL}X_ky!r}OgF?`CzT@g z(#r6IX(xhcuo~p8zZ}_wrlu#3VykX{?l|eHkIWrKP-;}!q-%BsBLt7e^fYm&le}MW znMI~koLi>YKD=dDUNrdOrUkrGcT1vRYX8(l$#g;+V{lmA9*#bXx9fEs#YRjSoXWO1 zukz%G${`{)>#c^gW@+$ZsIIYOdNI0DtN|f5`Le~13?_=tH~xI3qnPKOY*@yRNgxYI z`&?-aQ+X1+3+s1`_k}cSUfBx(G6HZSoi2T6-IHaa3Uj{^zw}3c_hI%*M@75k!L3b( z;X#|k{*#WZ(^uZruf%^?FM5h4;kHXjzk7xrd#a{S%WVO)S8&Mvdr_t@|ogw26V zb6XsE9o?2w#TpDnxGLWk%3l*6g{ZS-iCS0O-zc&N##XrvG%Dx%GV(moU|*JHqH1^D zyR}So>0Pg_$oG?XTrz9+SxTBCSuM*{wg2`QX1`Qg4H@1_^ZCwNDU4-lb$!M*Q%5fJ z8?#sKe{uCzL2-3av@RMTxHax>!QI^<0fM``26u-v8r&gxaA@4!-QC^Y;r4&5&bd$h zvLCvuy7roD%x{b_u>FImJN4^SviVzr7h2W->*Xhhv+oJyw|vghuidOJ+^ped-55Aa zc&6OdSSmALJKKxpKx6VAsa}SSQmxJ@4f1vVJT^wN}we z)pbr=>S-}Cu8K6O>3}`%GgRYRS#ddJC4j%G=|IJG1~>$8Usk}!a{tdSaAAZ31BsJ< z6W||Uep#Vy2Bi;^4)<{Gx}^v+|$xshv&M=A4R>qbdA-?en8>Rsd&n1tW zBxpLt#$D1h)b+$$N8&aZliYfXVYn}E=%Hn}JaN9dwi_#a(14&@rn*74M<-mtr5-+t zv1Pkby&)pFKo}zEitz;nJ#|sqhcf%0jX(e@%(76Lx_n27xDSu;+tx?>7u$T??@SPt z3WhA_Q?1p-&6XE5kIUgOEcVN_!!S07{owzTGPQ25fd-u-#>|2of>AUMK11xIu;w|~ z0&DozF)bm#l|;2D;=cnH)aP~BZL(l-!(y94F4kL9o^;K&X!Ic=8qka48=9MCD~nHI z6b#t6X)Ne_RYSbX7a6w?VO}o2ZxqAW*TUc+9~BGn&ix4Y^ZmN+*j!wN-sGn)hZ?YU zmzIF-ixlVYA6oWxb zjxPg+9T~u1qee7JqmZzXaRt0+U7!C;L>by`>rxv)u`9Nn|Mb?>;T#Go4u=U!kvKd7 z=QJCBw7fhuS*hx}M~8w5Hr#+Q{UQ~>TBcd7GweBdL9Ou>`U+;7_KmO9Pe_-vqb2#N z0NR|x4c8#hef@4LUitt*;=I@^o5kw}wjtSC!Hs!{+YlG$0pH)Zp1yII zQ?8^_@i)w1Eb)(34*ChtN0uN*$VQ9(9~S?x1g)7DHGOn{L+`2EL_yr-ld_2{?0^v8 z-+Y6;2xNf0?wm5yg3DAsuMFetq{L1Hdd+RSVGW<_QaC@zZbDJ~x-V=utqAHP3 z7rufPbV)xJ=5(vMa>`xS8XeZlYm#>>OPPt2>z{s1$Am7M^=p0fsWh73dtdZj=P%?e zGQ{HO`%K@b+yveeOly#JdCi8op7hcP8mI}G;A}e!_vfSdSSAn$%$vx;*6Jp>2d|$L zkGBk@`y{+RG=3(HbJAj{X&lH|m8i?XAI?|(D<_Fz$~g8y07>T+bzJ<84rV_QmwbP1 z2`>n#*6?+RNE8Y?xdqdxSrE6{tGntN26Jswy$8kv%JP96zDkUd|CwcT%Xo5~lFN8g zy6}T`#%!uO?OoXASZR@&G^@M190ppcS)(l$3>PdvUydGCq9$Ts)$esB2a~mUT^WB! zmB$tBnic&C2dy=S-i^si)mdt&Cub~(FZ9TrBb>l`8I+|s>3dH#kFA!qqF#Tjr% zM)sGooQ39oAWq9JRP&>()_M8^Kdnn{pP4u7eDKnWCAH8){;dBTcDd?SL;5?}Nc4OC z1z0uEdmXg1eOCL!ZFBVNz+FJ}a5ZZ8_PZl!*Sb;o zdyLD1{na0#2=s_eW{^4BIJ(%2Yt!PhgY)!9ij!2%k7rN(-hfxoX~h?}xjBoV2hTHv zMZcy6fxYiilKrfw`HKZ>7#oqbNhU6V8{9pwfLFiG#$hVfiF@BuHFE~e|7A+}-(ai9 z6|ZAT*QIULT@@|KJMgE+v-~tJEu#C3fB5NyeOEigy2C{&yZwM|eym~pddh)_OI{6=P>@&5{drNrmi9bAbd8uubOr1OM>5NdTEX zjyX}-FhN9&g5k1gA>YxvP{}0PMcCJV=C{XU!@Ka3@`#x+2KC}O2P#2x!1AQ2!PMl3 z;AxKPC+{ydh9YzS!ap_6X!sXeU@~aO~r7k6a#;o6Hr8syTW?M~7$hEfSBzF2Ht3vDqwE=# zCKY($;lx55;kLG@pLhcSVqZ8;biMHl7=5U%W!ps-5p-qq6H6tZPD#tK)R+h>oa{Eh zlHZEGTvw_6o}q@A8?L@-kj_XlKz2)*+ktx5Zg2jB2dtzcWF7*ggt@N>ZA5l@9ae&b zo7E`?{W*GozFz0u7mR-0=;XRnT?n@aGjd4Z9V z#b$R$!sZmjI&CNVP`DuEhTxKFwbE6lbE4o;qi+I<4VovnRYh?}IfcMkQTxx1lWu&Z zP97y_eH0?DwFg}g!Jw<|LgvIv?@JV->(c-}s^S@0sR8^u$j>-(UGKRTXP*`=CK6I0 zjC*P%U3%jVtja*0V=fnq^V^*VJMb@1y} z>p09U9s!%2!u=+t6LGdFuAObGRA{K+1em&2Z~D?RI!=wGCNI0SF9-f9Y#>{bSQdXY zv#I4)9N}EW`axx#F_jxc5NFplk~+Mg-B&HHlnymC<|5-tH~8cHEKi6MKk8*itr*7N zkT;tdq|13aqp|dU>4m7r)=&8Gf7pN?nmBE_ZOe*tnK+UH$4Q6=P>TGf6p>dTH-nX5 zpw|RZokt1oU#s)ZR|=}~*Xh)Ap1Phdlnw|MZ@S#&uS{#c5AjmI`~D!m*TZTkVc(DINGL zI)D!6X$s7%SZx>~pMb5ityf0;S~7ccb8|JPYS6$}fC{eLq76wFL<~t|2vm%|5f{ib zfeddLHgYdMi}%B#Di|U!Vgm_;}w1-KmoJORVnCz)kDhDZ_3$6Xh!A-(*@?w*~lED zm_DNWynNjA@M;aa->EfM>5(&u_}y@yqt(N$#@Oq=`$TGrv&a;oh1`g5VU1HB6p8Tu zy_$F%MNL(uX4$v&IEC8AG24UVT5}jEG)sIK3-QN*z<~2l-)sgXKjk|LGdT|ddz}CD ze1C+$`3sE-^Zl7jTVFcRu^wTFr5Jyff#WYgbsGL()rB!HT|L5T#oh9E_}*ms*@C}+ zdlbrrpSHxMe)+szV^F+VsfMMFeAPF^9lpbbJKqY$@vDR-#4Mx|9_QHCDA%+)=(=`T z8fCDOW;9+#h|aZ7K*XIA4gyU5m*KhAPIDkJR7-6*pBCR^3UE%G_u7#z!J6ez4O3Z9~VHC3<;%kOL{Gt zq#p4F_0S3u`kvScc+S8SRoxFquhT(6cs(;9lj`Dk2gFq#V;6H>0bOW&Q;%y7Bx|Cf zKm|XTsiR=gTz`MOw9*Y3f>VYWU!!3fnMC~?;5bJneUkc1Qv^dXeW0Js(CWR6^y}gA zEqrMtb4)m^5Q}YE>)Xt0J@`-d3m5X9p@WVL(do`;!{mg z>aZ(#TXpUQC-O^_+J+_0EHlvPX0Eis4k~0ho@d~5(6;9k=&T{ysaV4W`&J?Dn)j{5^;c)*P?gUi>tfc&7BMtK2%w_=eBE4jbF zZxoy@&S(_oIal&yn^S86k^ykcYHsv_8*LF`v0>IX2vr2eYPED3_l!j;O_wUyTcc^i z2u&3v*1d8gD)HDYhUR=qleU}6{o*#;SHdXMk79Po%;!D1>%O0L!;x^@-Vt!yazG_I zrJmC+eGBn2EPq#Xg_xGnyUwgoF`vjRY(7C-FH3Muxw)!os5AUl9HmJRuxGN0{Z>8) zphfQS-=>JweD;>_O?eOTY_v+`zX|EEz2I0^U@y z@|q0%TD6A>^4S}Twa*F&^ZAhpD8Ns{Vyn|0S*04 zy{z0)q>jhzYdyd%()0Xp>whk_q zjdxLT=S|X8HY5DiH;auf??$; z*I{NqWI^v5{HXTW>=1j5pNt=#Nf#p0a*X+G5z~WS&*L%?e({Ty6U{N(A}nIZqNay{ z(T>Ea24hTN)auVetBxgQyW5M_OEx<&gY(y6_JfWY$d@X-om$0KSuGM83Ljn{@C$6l zF{%PUv%ukV+w0x}q!aGjgIAkfEHo<{;D~L{#qo|ZqJ&ATqSoqcQdWi;wOs%G@Lx9x z5!6(i)s*mw61{U8sCpCZ2n^#AkX}V$t-QaO=T;kHLvy(mPlKJtzgXw}e+~;>SV)@A zDyXSwzf9`q=4)qWrT6Ahtq1zWoE-lD`5-)`?->QCpPCE`ABGuTdb&#jH>j&fb5gEF z1}LRn4{wqW5YaJVm?A*Y8EXc7ltFk7nYCF5ZhFliJLbH7wrTfq!DNa>sA z4Y98XSh~gic219s&i8XmyEs-U=A1zig@ilj0s@{MUE#ziX$CQb~Vh0j8y6sFOW#=qyRlD z8m?Samooc9Mc6PNUT9{lh+sC#sP2%FR-|M^XcoQ>a~QY&e5yzKDe|*ng~l_YM*o95 zOngdC2<+3vDZ*Yn&sDQ zG_JGYXtdk0w7TTb@-I<4*u-%pcXfx^-WwyLeqHHndKa}zraArIcXXikFDQhjK{6rj zAbFT+v@e2%>%m(XqReI@s%4yT1AAElxmvO2$S8qqzPO^_z*~K_w;4E<_EbRpTi(0* z{U1nwFxqHdTbBZle}h+ZY8-+9M4eg)vdvqk$ds1P5ZK9Sb5Y_4sv{d`{Jyu>0$K&) ze&<-^#%U?67GP0*nIRVN=CYR+S%qbQSuId(r<5kyV7LiAbC@xP8Txt?HHBv<$T8q3 zE25AQhAYCN=b5Ww*S;{eHppYl4=GG&2Y9nIfL2o<%f{s1W!ue<*P<-?R-;ow2cL{spcc)3Ux+7K%Wil4Oq{{HIK1^ouFGdK$Qw*%m z%&?(%B%HTb+b+`-Me^FMs734e_WWmYAYk?o7TM^y+W|^dGwU`@^>loGyh>Gqo0Jwg z@U-AVdG}urCL4JnB#2A~?~d7f+Pp7V|2lvRJ+9krOfunV<5SSi_wh3}y-t}jY{udw z69$R>#~Olp%bA#P4~yuP8P{~^b`a#L+LSMUX0`!6!ii>l91B2d7PL$$ z^aG|FW|RnI;~uU`yENW~x0R661G+=bjC*H*?e}4tQH~f?tY?AV@^o9%4a#!Q!8Omt zEUuK?w>Cu5u57QD};D_988)2c^imTgd)%NbS?ef@N2BNBu;w8@bEu5*jI)}zJlkzHJYR`)mbwKU|_VxY&i9h&gPhW!^W2Ke@CdWU&v(EGBTrtSGaN8R8K63`(gL4wsi ziI~cJ@nxPBxK?f2s~hNMuG4LaqTq2b2`=7f882P(ejBFgB=q|L<_y9%ji6qNaTI~K zWYj?|GY4cK-h*+pW9j+qoj2x)auWN3Z@1ilnQ6F7b%H0gJ)7t3N84;x<@eu`5S?Dn zW~Y~lMDns@C?y8^&5T=HLJI&(=(wV`-V`PsYar}ZIwAhcnBoyXHnw*~CP*~`+^?Ag zxcqiMIZd9=z!}ao!@ff2Ius-dU=xvGr-4>INMkHF%(il|uHSuLaW=~0n5v^Q-NTF^_bFe24fXd+$Kv59n8KRyoj{`61)iGSqG2ceDw(^>6*z)#_S6wX!&$5#?g@d@SB}W zA?ySYhq=Mw>q#0&YcB4zMBLF#v{(3jk48I64f|j$1E=FE6s||UQzZvySSf4p*~nf- z*d2xt@_*h@{`(k`>>9q*<=}IkSR7S!^!eI18JL0AEPV|Brj4FUwVCO6W5X0ivoMSn zurdx}cs+`xJ{u#fhG9XK)qLCzCm8`*1jf5=J`Hg9+)fJTX#I$dqdKIS4ZTi(ihvuJ zPV+q5P))}W6tl9jO67EE2vM+9%UhY@FJ!KLG<83mKD0@{SDi)`W z$-_A)k3W9Am&GvtL_d76`_>FJx<7HHHawdt%s@zbk-Z9Y3=!a<`*!R}*SW{L<9ITs zmG*v0O}0mhkouT0H84Y|mn7YihSy0)H0HbzKAzE#9`JB9y&Hxag8O=Hq<^W0pfSBL z%%?z35X&e^L5WXIAFA3&zs;f4bEb8GEo^CC^LV+|{3y3XJ-bZabs%dv3+2rqK7uN( z@J^TW05z9AL!%_yS|kR-@AScEgaI6Jb~0nX1um<{>UOdPaRL z!w2%bx&-) zx~YB4{1w?(Q*{QD(MPauT~GF`&^Ldw$?MYxZqrd9kWwCuHIJ?wDf_=L<8@+XbBX$* z3w_*F>40c%XDI_SK|e=EY&$g~9xm2d1|ty`Fp?12i=(%Pw)3U3-DcTgye(Vf-2K3) zLp2krQKzPYEPy_0U*D70W9xe=%LfWNhD-T+?(?WIT*$s4(ExT zXsx;nj`L166n=BZzxLW|jn28}Ym_&BRWKJ6J?|$bmJ_+25_;o5)@KJv^;l(<(p3ah zKOzxn-hSz84$U=uhgxx__!5C>93F~@hL?IIeQJ}!;XIKoSk=IgIk*9I>$eJ|LuufoiYK(x_M|3m}xdmGtx=gXsVUk}ymsQm8+^%40&A zy*)*0kJT=(C|_=XXl~$Dj#IkDUD035@Y9U`^he%cOu{0FAjHNc)mWY_v0+++LD~fX zQh_5U=L)K;L*dD}J-SGp!Ygtf`%0)~_WPNIu<9nCRi7(iBPgYKKoDjQd;hfnnM(!g z7_aB^Phr1t;_-}FuupCqxGwg)urO2i4LN}eYl47&(Dv(P=jIUH%n5lOcaKMpRNL+j z0`^1}_-?lb4|C^N=g%hwQJZU1%R%YXW^q)9_LuQX3uQv{lTkckGA-#Au6(1tWUq5w zHg>8Tt?Adj-4@qVPN7VV&kq?BZw;NfB1nzhtMn_*@rtR;km_>=DBG-oPC8b4VoO zHOuKA9HI2;R>y zBcxScZHe{T5F5oO7~uO{h)^2wl30rOKX9?c;jVF1wyMPGR(!Mc%P&;O%6mq28s*2z z)gm0`g&|Ydv#!7YQj|AX>RS#-YqnXOxH_ww3}a7suZ@EaN^tk1)KLESP7G>+q2Vy| z%z0GLjC=}aA?9zG129+11bZTR_6r|>({$`?->rzGn>75QrTj73>Hp2=kbjev>4-vF z(-yB08N#813E~e2DmcEvlbF-Gp#62j@0F=H?S+)6d~>Qu%TlzX>GMIyL5FaxQPULi z0el%m!89|2bJ-0Cr9%6VCXt<^5(-!%ib%y0Gb!F6&(Q1JyLu?3-!O_iF=^4!GB6-A z;v1pEYcez?iOZ(vw?&$6G`brY=6yMjmPE&6K8R(qTN(**Hd+BEZ|MK958>ToOGasM z*fdXu)Wqr*Lv278VaVx^i91V8E%p^7u7lr>dZ9X=niP6F%4cz((A~aCtp5qXtaj%E zYUG<_6ITo}{&9r@Fm8pngxU@UL2a@mhF|~gN8q1Vni`-UN3iB+bkr|v`)N%ayISft zs4@AT9&WeTv>?5^N*I6ld1&yS;wZHladxSwW88g7A(w!M<7;}dN0(OwhQJ?GPf`0M z+Zdx#|M6l1HIGO%+n;3ijdk-X9@O9F_Su+X0=J4uSPywiyi8-H^pE&cpNq3u9F#m( zAoq>@hM}NAU2vs>)k_r3rhGZDt&CiT-$omkzegj?F+UeY|2OacUngP{8x(i^n^I8g znw1+DyHAOHR3)9!Y7DMDgF7;&X3pJ)I@2D2-u4BzRRwjDPKm#LKjdn56(ew|lH4f8 zSDaKpl=S65$02Nx#9QF))&EnP8kaUc7h#+Xh95r50z(Jkud4P9bwlNQ50}l{h$E~kfW{&d$da9C2 zu9DlY|BL^Ql1B%mN5klR8)3M?9Cu7ma;{Ngf|`AUM1|R~w8|3i$q!VKk56`Ez8 z*ZUnirrE3}Bq#sY>=_&&74bkYlNfX*qS*wtThpE;8HDUvJ_ua*?QX|@9L4r*e!g#7 zgjh|_-Je!zjWnWvn&!WV1$(I!!WljkDTvDC4SyzewXH<1Klfo&L8)&wEF0>|>q?O5Pw zdb-otJ}0$j&-3|3TXaafFO5ojum?(bi$dSq^Yofk`Y=|)H$Oif73v6$F8K=U{NBBK zNh(Ic^8yQ_Hi-6Zo8-f&tyq%M^7Hco)qnB?0a;20m4gh`hB3NmZ#eWn3A||uTD~8JiICp?tK_kPQeN{r_=7g#IFjQ(!RH-f^tQoq1vPwY#iG4z3r=S_)k_j*v zO~|Wa@@{(WK=c?-O|)ZB;sjy$a|2;ai*(IXU0oZ$NHND~4_A93$}UcnLOKS6OwA#^ zEUJ|;z1JwuSf{_?sUyK*K(*m~i5deXp>GfPNE5=;CtyO1|0hn#63mwS5+0*nMq<*O z>q&bNaJY%Gu)_xNPZLk43UUY(O6+d7E*fTQEzRqYdGNLl! zS!vzNFIS*$kz`?;xZR*227r_29p{I6twL;k_3NO$dt3ynJSJsZS573Jh1@UN`ezj{ z(a3vZ$D^5;r?CWFJ2mVMn>NTodqQ96l9R8A<2MYv?tW0{Yo!jnE{qx47=_xMQtzeR za$ZVS@GOgO$e7OjK=HiXf{O-=$Ej>Ieka#L?T=QyakYe6zeIVT;sKuZzN4=8@pwhB zQX%Ycg&(pRFWr~@w}+snI+c}LRBfIHslQpcX(c?R;zMg<^{fB^5s}>~_%K|m_z;TY zTFsD$R&JA@u;(r#zM}Wit37NGt`R0qxUbX2HY@0!JAx6O_8ZadUe=qoN%3ChLfzRL zh1y3DHSO*Wq5ZuiL)sj{42j>)k?RgX4m+mmmJ8K;v58hXdzlSlnRAWx4C|vUP^X)g z^|Sudq{W$Yyq9;49Nhij06#A8oVu-GCn(jevCwa&N~OXN3B}o#;dh7!2sMJo1af;< z#^V%ejnR1Q+CV%InleyPe=2A%p;(E_0+x_;p*!)0r3%ib9P8>`rK*-)S;+0I#7H`8 zTl2`}aowc{o@u9>kiW2)csltYT=o%M-x)>`juKMWLx_aS?>L8zcwcfT70qf^Sg4)L zCuQ{V@4YXSat@MusfJO#+@m|;8ckjdyh-wqbJ_dQz6#7oPI&y%KgfPXsp#h;K67#W znizkb+>ftW+;!6JSty(BO!SdD2yQ|4e-a;`UVZV_W66v`Fp*{hpTAceH?^ zleQQx*^fU5+N+*+r?O|5+(ogj`k4Y2MB)K%*a!z$6JhdJlG)%=vX!Vw*{<)#-lqBc zi6N*@zW33Mj1kc(7~jZOUQG8-4!qa=@9(*LS}%R47&FCzVE}maP|`CT=J%OBq_Tx_ z&TY6JX%0=&DGXkphqwN#N#S>mXJE(!b7A2a+IoS2-_? z-(tP|pNb^>v`l9?Iv?ms*df*k5Zn&yfCk%5qdpRCg1AfgWvuU=w)pbNet&KL?rOnz z&Sa-Kbi7w4;cXKilOxIP^O0ek<$OFBQ&UoY8|&`;IN%3lvvt0_Wb{d~^oF)PUF{aG z%?Qo_O20uK{4pE-DP0yNlaFF;_B)M&*j?_av8+wZ;>@4$_NV8SNBydIxnb!2 zb&63ErNyi6hMVoi_O?fl0E7W%zDMH!UMqW{0@cnC=#tfE%PzSIFd(W?PvVEP}5 zoW1UzGU5jk9zs8A6;`7<9qpk4<{vrl?X>4l`_`jng?Ngu-6TPEM>$RNMW%mmJ3o7s z%W3Zrm-7Loq&)`i6M7}dc>O7g@QVD@j6M9iMm1wS@?}r=+?yy4?R85b9s=U3G6+|~ zggn0}-*%Nh`e7Obh6$=_@ma`qlqkGHFe_4JvEEA;wK0AdzgZ3jc`e1o6onl;T8gE3F z9^WRB5jot;mCaW0OykoTm6Q=>j#xIf2N`0p77 za~wsrm*kVbAv$!vX5Y7``u!^l`d;eA(!&nuD- z@i0>pQITeJN3O6H!*!(M9Pq-p3t0kU2R30d)x$i>B-4U1j52aB6-;@eat%mCOAPQ1 z5l3(i2oK1@XS*Cu9J%w|kxX&Fg>g_$3+U&&@79`;$h$a2GIe#IaqjNoTOD7Nm9Vf6 zbw1x|NTd>dy=?#Ni2rL^pnWa+kcT}X5a>RJXT?+NQCyn$4eJk?0M|(tqYeH23pVzV z_9O7Va!-*)O4dX{_J|y+^!p?}mXbfGrj*O&S>TwbN&bd>$b825z&`bcNv&AkA@c9e zo34+mer7=ouZQlINzL)jhR|7hi;9^xHE-EVgZS!x@`idlB|CAul110R%5GEv=6SuZ z^PE3t*l?W6>7YzVOaxXlssrdIuqA!|*;;ms`KZE;iC&H3j=D!OOBz;o9 z-$|i27rFyS{u$Y`Nf z%xvfObh03PQen32=lZenom@;EV4~)y|6@yf88I=Iem_sv^StPAO@pP~pr#4qH1cMV z!Jxj)#+6dTEtU_E5b5c*La}cq?A)$<$AA^d%Pc@uw{4?dl}LSt!gTjS`3Al@Hq3wS8ZlqdNpw*56OK5rL>SMjv8S-^MJ?-YY?5KbK#EJu#lY8e_xw?mEzsVTQVpQhf@r5cn#lM0*CqHR>xyem3hrHRFEzhtJ+~W@`W)n`smhw}dtM1p4$gczb&-r?D)hog7$g#?6=$Bj+&wI} z#dI>8twzml77Gyk(z+zJCjQ@Z6E!eH!SAr}fwyJvwwpSGyIMhEs4j=GTwGIrzNZ?wkpl!0OZTD8( zGIgJIsW*BbJkzbTvBe5ZBb)UQlc&kj^q^`uvjYS8tst(V62&@7 zRe={A*Fe&=J36Hxco{T_L5n@shj!CHgq`ZKcmgso!uJ?LQgCi*s{FKm`*1xO{Z!~J zdpM}icD!MVh&{DVWH1_hBi!d9&eup$DzQCiOOB5wnoQCjJhXj*|BoOq>voYxV?Akuioq=7tNi~IIT@HE2XkYM z_!;K9_Ifk=D9><^huPsomN~jf-4GT>FP=INz={k|aM6c=DQ2am<)OYHHbuHG*pN$kupJVf)M^VEcxJUS#K7@3WuGwBM{+aFNY-zcN(+0&v*InjuCS=e4rEfD z`WJ#L+3HmWqM_@>vic{!rb-Q_oC=250zh7mCuT-KhQjAePhljCWw`A@D98hhv%zS< zX@i~4I2Ok)Lz76H)cHA&y_nB#2?50nHpwpK@s9)ZVjGu4=3PxS2|@JBuU6B}1=(rB zhJWAM#%KuO>B@W19m>AJHNG91<}VJMT_UZmydsTF*PsE z?C^7C+}^24+aH)ku23^o=Wx4ca|9X04ZlP`5C?9VZ4(roO}{m6jXPBSTS9O0g2H7OkOiR5}c+yx4J`4 z5r;q6eoj0PYdDwcvz(4+&!lo+uD8Y-MakO9c#H)Z{3#^mXsZzjpfH%@e|4yP3UPU% zN%kAUDG+k1)8KLi=qXv`R-K0CUf14i(%)QysrSxA_WOL|9}_qB zr8yjpg_!*p@Wa&2Ln16|O|PuSNhFv%7qa&^fSwen%XfBxX(wubjPp_@+&p15I#xaY z9I|>_t!QEJ=wV9(`3b&dnVqs5CCAM1KP&Ic4E|!?Rlc4PQhC0LJ)&O_rT4#Et<_f{ zDzb=Mz9x*CgG4H8xJ{82#yoKLwEGJQyNxV|4r8;AeLp&h@X2dph|{;FNnoykRooar8Fro+O7(_|DsL@*LW5 zCJKljESRz-wC-?NW7a+hQnu=xbUFDHs5^|(_|3c^@AskI8FnRScPY0kN-w+=kY-fu zGLn#O7Q0tGtx#Pgv?C1`QJ&7wL|iZigQzLYj#@oqUQ_+TGVz4{d~hkrkr0{CI#Qv{ zQS~FRBkqY@;h7A3iCbX$)fH3Mb7~{NLY6n`{Dpa5kn_og>U$hOZ z1b=1!>0P9p`71o_L`bZ1@0ILyLMLqJ^ICuxhN+@o?rTY zzRq|h0~&ht542m|(~3Qym!a{Gcx2v#S4P6lL$W?AG(yq8Zo6Q2&q6^xMlQX%#PRQzu{R1IB zloky=Zhi*zJb<`Z^bZa%TQBuj@%wHT>2Cu^O$C=ely%9Bz( z@R+T*)AbZUkza*HGD%vgg{z{jZf@#SIHohJbS#e6$0*eFxZ&MHWbK_gK+G8A+5HBa z9Q*!SNLJ|(n>ABJy$<;fcQmhS=v!U&&{afC=3$aEz9$j7MPdd!3aQ=Iy%Y3vg)20a z?i57Twc>iV-l4woSl0V1ep8@$&D#_^j0sg!VDPU7AUps8XzpD`RHyg#@y`GU5SnFP z@w3JIVqG1FQ3aRBG2l(9x}U50NuX__?Jrsbv+8&7wojAf#Npv8eRi(k{-gq*E-SWnt~U+_styVz@BI@J>?$BJu+YoaXHFfprZxn}M`{G?HRf zGSCz}xnQ&nu?5qYhp`TR502g@hk(t}{d}-bZhWIO*YS%AdImL>d}!`tV*EFMx?^t0 ztQ!RC)0F&tniu&db;X>oCU?jw(m0H>S3bF|B}>n_X=Z&e5>(oXkT;|f7aXv79wD^kiOA~-smy`ci~-S_>)bvqD_ zxcc3OtR~`74VYKL@KZ}+ zRyDoId*m@R`9mG z!ONfiAK%CwTLHA%|L_lEfoD*tGLIJ7&w)F%9CnHv$B`r!mp?I5cHe7NRt^vWYYwl` z%my7j7q`+5h#wLuyg>*qU3%olWTV|rku=#LuOJ_v%lF5#W>`5R_8-5FAYxu5;o?i* z(>L{ODYq}*uO5+<8?23#AHj$SuHWg#D~Jv4I0*E&?r@S28e(4s z^O{1tN=Z~rKC#oZ{@)8+iQE_KWrE$sk*50eqY#W9)dHt@)1rQL5RiY}7RuACb!rH6 zd};-3vAThETqYL0hpeM%t=DnhKo&KUN79|?3u+>cT@pW!y!iSv(a)2zs^#omCh{3c z`}8?~dQ|Utas8R_CHd7Y4Y4zlkKy}?~z0d^*nMVNVPn6w_wk_-+g3QhscIcAKcwQ+1fH0C-mOpLhAky# zX%_yy2Z*LKUuB7Gnr)Bf#|oOib|o~fd%Kl=CUfhg)z;G5JN9@%0nit!Hqp#~mwc`) zc9`2G`gJO6ua#+3)pC#y8i2EpdwL`hdq1CcNeGU|I!@x=7_mr67&lCukh~M>a<{!V zUn`?S@Aw&|rZy9}8siu7zT-hV6WLv-0;J+TxcyEEv?Z#kZI^5N@lnjo^dqdiK@-EM zh*7w~c){SVfhEG9a?rJ{Vu-G!jh&C}m%|QOGFKaHc%OkAQ8ZfGGohmWv2!+Nzux~bUD-%N{17Ea#j|#X*@aC_O-h#h;hNfLsLtbg zRxY$L5w7jqY9%j-Ag~k8N{%e_YnOxw%$0U3!BFB_ZI`n)G`YBZlhLrEB3mAp-QzP> zYa$Mw8U?Q#h=2&iOoa*p zo)oi5V&*yVDW~JoTn)(<-0T<0bk9lPx4|A+*G?9ATEM4^S~fjBELA=kA}1Ug-ni-2 zCG3I498Kj8ufCYhZ;dxX<46HLo=c|9a3xHnd9(uK6il)AbR4Y6iG?SKJ6Du-(*MM< zStg3fiJR+Vb;E3j27i|V;>?W8Fz>_O?pwx-;Zn_DV@|{he>BAd(b9Ais6z;-{mAl3 z#an-!TjO{Aq!-slg2DU3tH2j$Db+*AxL>ZKRV|V*6XZxl%A^*-3eO=}eVz1{w~d4s z=|3W-+b4@Rgm~>l5?;hm*`&FTQ<=INMh1I$i!(v+C6ne)RPC+|w96UVb*d4w8c~2z z^pMxc5DmD!U=L1s{^z_@Zn2}K7bcAv&8I6lS>2}g8N=H6LwFI2qpzuYs~qqvh7$r; zQD{|5FRFHPs`{54daFlj=`=EZx|I10Mtae)AV`!?%OjQ8J|>T-F=`}FaaCLm-GbU7 zAKoEdH4hfD4q`#?)Kcdg5q#*^QPaj7r8bZesGF5tzpSZwkkbw-D1lE5D4Z<5icN>I zBLQsGsM=T%f```f{c&EeO_@*5Y8#G9K&^UT%owXK+ygng4)O#@4rOf1+llrie6tH> z>u)PVssA1#6wvHKxH4*si1tVr3#0|N6*wGoSUSN@sA%kk6~<6VSc_$A5SJk3FzT4Q z+7aKwi8Y1Kn9D-~YI5lmUU}Rv%ClxSlG3I$@F(};gW?~_jTDLIX*(M}n}+NsDwx?& zOsk89gLjwf@EM#5Q>QzobA^h1LCkcD@VDSxK7ucX5}ObNj(>?v(lfXMHuo$~xW3VT zuK#>Al+iJlhdPNlEJ!+~W!OdYMS#nGf>m`KP~cTZ=pqX(WEvFucg+wid$x!(N8GJP zrT+2yJNI%!k!Ls_^#%FfUHv@jA=E@vT)AF$h1}_f(nvoKbRO!&9+`ca;nk`!F~_X( zkXp;npqXAaNI$Y=D|bz@T$gGO7~#YOHh48C4F+@$$5QkFRT7Tso=RUE4yc+~Sa=KwkWAnb#SM#Wb0 z_zMwQW+JGZfp~`!Zd&lE?9GYnG0m*kjCw9HKtD;;V@gZ`p`o|&c4h5IO51rCU|jrn z%6`V@g1bZum-u}fp+R?Y(Tsf7^P|+p18+Vnrkv)<-DbITHA!awr4RlzfnTHnZAJK` zSmr}@O@~7NA6;J=SJk$?Euj+9-6@E4cXxwycXxM6DGkyk2!hhE>6Gs7l-hvAhE4ao zJm=i^o_p{4e_Fr2zQCGuj5$X<<9Rl0+yY8evZa&n1z<{L5b*YOsxvwx7vjT=0|i)n zc7oLI8DLr69uTeM$-gF!Izbf=vx~QOPV0T7e^iCSsVeNv2u)W@^7sstyFn35?mFSF zq8AQrEc+317l)0XS4>VynHo|^>$#o!xCIL^(<#JIr3yY71}@yM#Xe!@?wvg} zD6ri!p!*oud&F@@S+~hObp8@NSRX2M)p^(-D1f;Qlv9NXQ>1?2?VnT|73azXvv=!j zg+rIR;Qedky5pSLylZXhxP#R=^GzP#gWhGjUQz%_YefSpv*~`~RBQ z`dx>2i0(YHxLgrBm;hu9aKK}P4`QKf* z5IgD4b`B~v%)u|i1)C2)>Q>K1hVFWF;5;b z+cwQ6te|U}d6I|maf)n}`)wKtn(CFZrS8-#=J*!L;B4=0HPJ8GK219Y>Who)y+gc{8IJ%iB5eF(dangX|s-PuTeD z`}4$h^t2?=btwqt*QLH|Nk4v$kJq7UMXAt6<7UI5CMkgq5T+iR-={v%4qWKm`!53LN3_pEfz8(K; zdQ&hiS@85r7L$*N>mcv$2#fA3zNt_Rt9x!O{jBNkV9{>R-wNO%<1a$=g73j_%U_E# zn_NHLP-O^ojU*~2EWgjf0Q&RIaNV}t96ay|}oh8~;8stR6Q z4o}7S(RG`HNlG})-Elt=Z~XcgW5=&8!RP@c9JYX6D^n*_tD3NDk6a&YG{$xa`{|Cv za+ec5-p$UT$b`K;oeH02-U_aj@f(9D@X%mC$bj7ZS7H^e(0dC*H)}0*EvSSa<>NJ8 z9&3X`@;B=b@>x2MZ_!8*UZO>>XuUbM$mB=_IcMPOt+mK4Tk}7xSVvJyV#_DqarnjM zrAHsO9q`xUyA_P^j!I-N*KSRN+wFWlTrr^)|NPiGdzX>b#G0JG>iAmZu{;Xf>nsml z{!TxzX&LYB`g~n+9$B){Uo$*^EQ~Whg)?%(I+wx73}Uj75Yc&MV!WfE-D&lb-0WhE z#>Pn|IEK%P^IL$v5iYgQX2|pQk;tOO}PRs-`@Mty|^#5YPza1X<8OyVQmmP+6q4@iY(Y?Y_z@hbCsE;(k1^cS>|1W1P_4Gore#E~a{TgcL<1=$T-_)V*} zD1Kd0YbHt!G~^e@sD=cR&+v+ND#lyPB#s+N#d+ur+PBv*-H8F;5^M zx%IoA_qUrwDXf!GB(Ndd`|4d}hbMR>L&Z=PBaVz8mynQfNi~)Z(nRJ~{#^c1*AIO4Z@|cZ{J8_^ z&jCic4tGNjFZ#8zgqHmQD#n488=TdPo`Bw{Wk3#msQ_ta{qajvWI+|8~qg=5LB zG>6*kKy@|Bzofm$-dSx02T#sjpw~|FPPf}bAW{n{aeWS2S&3cmCTv#^^)6q;#x9>z zE#>ATv-jiq`)&)NA-D%ZTY5QEr-ep|r#B6#94cLC z7V7L8Se%YqS=t{j!a{2MYxDe8ATvZ1cTBt+g6OO{P^u<*#?@ z;JaZ|bYV|sDj?G0^R!Rr^N_=5aW>wgta-Q(N6rU0E9_UBIkSa>9&atXQ^oop@$KK@ z`w+7ji{NuRW}8&GZ1u%SZnytqaN~#!UvYYNSKrx(ypN!d12bscie`XQq_h>%+{^@R znf}znzWH~zJ&OFpfHmn{kTP|+mop>lA=OYeY`ME;@>hfc0|UEShCUiSPKtX|Me=*I zwOTX`2hKM*5z!hN`B@yjc6PR1Ae(8}uk)4QiQ~Rj-)fFFtC95ILrT$<8F!I{y{bl9 zWFOsw#C59PyqGs>;I3t{`Z%S1{jUu15PE=`nMccty{BcQAT27@5D9Z$%KVg*de(Sk`i9- z1zB~wSG2=gVFvtOgotAgp)p)uebYNHZPc*H4xtki;$7^**CY$zlcC|tupHd+UY4q- z;Hr~E$&E?o0NEw5hskLR1dv-9*Y!=4#<#h?Oj!R!Z`0R+8^6lFXFec^wXv^O+;!`5 zpm@+GXtUiXuTFyK7EqU(Rr9YY(SIMBe=-r|J%=TEz#JRjioIrQ$M9)f^DjIhNkm$C z#Q@zp2SU}qIo|IBu`vf@?|j=UWWb8Giy%THtlXd$&Wm5T;+=}Ej=d9g8>_xL`p0NF z_wu%Gk6IaX4`Ca3G%_K9^Sw#IX&RX?)8nScvYcHU zzOUL82s+MADQ|&F5u*%^12e7Nr)JU)>uyyqh%QCR3fv=6N!|+hh5>}fVIMytO`}4- zdeho|soI!2nUZ_O?SEsI6#}5pu~M+IWPt0Ujya7_z zyFrguJGBb~&=&9r>$_$dmmC2Xw$^*-ut_9nh;9WdUKp3Wf#UG)e4jC?nG(3B-?Tp7 z9+&_`mQo7w#H<4TH-r6kUN;}A99NrJjHm-NW_wR6pKh~9I?}>Uw}!e3q)Drt1MbeN z1&8J#f2gcqyZio>ih%(McqA9cax4>v z%V7yyvr^Y0b0=d5ZvG-8@0+6Ve|y4T8|T)RKw(2K)lZZ-ECuJ=xT zk4t{~S|zTRo&`M}u15lN;fTp(VHryu z_t~I+idIPbouf_u70BN;sElLfLxa=0P=2XGzjCI4EdDuCe<4bojh9YfgRZ?%TjA~L zZ?MGwvGV`uF`{PErd(A_avH+;B+p#7FWPMXIzFta*C8sz(ueo8vrhP;0>!P*U`P%Ue>?=lX^@7fn8m z2~n@XQFZZcU9pc2K8-N?9Qv=>wC@tO@_MbGRhNEV47q$6$w>yMJ44#ex~44T3pv}R zx9`85oc7C0d?G_O3j8ITxGEagv zERJGXC9*A)MBAv8>^T1WW%KVK@NZG-f4*$oKybIM-Q{it`Cy2tboYv>cqBw?P|c zt>-mQx^=h%+(9$TUWW*0pqJO_tY!)atsr-XdAK!!F(lJU?;k)36}N5Z~$SEqcPFCJNBAtYy! zOyT|Tu_$BgaaEuLFf0baX>GjxH6tGVMrYN1+{ik+`7nTj!tSF}`q6~}|a2pk8cQaDk#RBlrWGC8@TWV_FSq{^_$y3$y ze|nUoYLaKkUz>Rods@B$Fw$FwW}g!g62=x87-~IZIT; zY6p!{y`lo>KT$4F>c?*kZ92*L+*On%r-!p|0ag^oAmi|edm!ZLesv_dW<)c6CD-D& z)rVs8Yv!8?!1h78`O(Y+fjuC(Fuqtw5;XpB(E-G2#K}cU|LA2!+AbHcJ=hRN{csTyJ z!cm}AuIpeqL($e^t!&RxmUjo&>IT5q#U8#tAh5^-9uSERm3ud<#ja8|#waJsoR znqXPf+2faE{T)aPBp4`OKM=Atc?U-l>5#s`7nX z8;$W-9(5=t2dPK-?W*wg0}#e#udu`~ePK>PyDcUP`;9CXOED*rLFdBZPe(yd!eUps zZQ|9SfrFH`K9!Pe+D@z)6)fcru=ppMbDvKX(0ET#uyu zSPo-7tIKN;V&K+Qg+bLVc!n4DR3Hh1Y{4gZW6)q?hRPI#G!~H^ z>ZQp9pd0=*(O{}5IzuG#*?2Q-;+laXz3<)xg~@O#;KYuOPY%H7Y z2;C*{aF3PUpxvy0Y=V4x7g2Tuh=tMaT*#6y@5Uc@jId=xWbTBk0|pPm=cAe1@z;D0 z985e0FJ*x`{@x@NNKwHdYc@pT#gToeGI&7pI-Cc zb$>XjHYj01pGRMrbct~><`azAkPW$)LC7cS84R${y6R*Mk9|avbWBDXFVn}>mBGc$ zSTED$#~)<&si*xYYhr3x<5E-1qlFtMv6IE&d`%l$CJra?<#}$~zEz$bytQDpU{8Je z(Qv*P@=DPef@RU1A#jz)gZvXw_DC8#y)(GEEW84}Ds-{fnuR_GY^b zIvINh#=z&&I@mN=WwLkf(YB7gLDZYI)E@MP@2JxR-({DZ!zxVZ!OvbZ@3iJNA?$7MbE5~B$a3W>GbQw zu;zwscy^Nmk}}H}8ov4{fx9vExNz$wX#N%+`c17^p@pNm)tX;AO=eZh#z!6{Wri9> zpOF)3sL1yJNF8EVr5oM-CVe$1=f6$qQoBLD;?qb{}H`zw|Lw(`RbOp27W~>Xh z^x~irpVu)Tfp#v*?<~6rgT>_S>w%bc*~X9A)BRm~&9;JP{|a0>9U?_MAG-+F>$D7= z9i9!^J#JcM!S%-LFMlsBX?*huJ8faRq*=}nvnZG`HMc=QaO}&q=J96_uID2Upg4*1 zSu2ZFgVD8^nqq~F)?URHHl49(ez%5EI3L=t-~}F!-T&RaU@GTf3KeygsVia6IsJZR z!$-@Y!yJbWu%E-OPbtOddut!~<3|sB^)5t`!5EinGf)*-Dy1E8qxma=fRTRCVOCDO{l5a_93&X5MmcL<=g#1h-!usdxdMyuO|(k6uf~O+ z{Iy#w6-(y0a1nHpow<-yUMG!K(YeGx)O(>Le^|crFlA>9lB2gFZ zeS1zYOkz0Hh|Dv#Vxms;)7Xi3*Xqx};qsYTX>lZGdRRwmb@bU(s8oFua1Kbt%DG4$ zoOSu~4HaC`{g?v-iBz#G-<#CkbXozNQlkdCbzM-@HDe;p1&OZlRD*I}Rp8MQi^UN2 zMWX7)b#?d2oGv;KT?`>7js0rPYhoU6mCU*KUFZAL4oVWj0Vh9RiUUbkE&mfXerrs2GZ6|%0T$}p`44p;nkoQQjR~!Ls+oG zr@u7i3|w@``bR6#*^VOkW?7olhx)$w=|VW;tCyMCdql-yIr;AN$uEj~$fv9To$WNf zK;XT0N!d!J7mAtx46)pohuAkhk6GJNJ^Llc})NjnBCEB)tCA=gAsjh!$I2r&#@?wy+QH(GHF?r7!l@!~;MJx2U^7 zrvuZ+fM^K#P;`vNr|Wp(>PL|EMt3t1t`Q4j-bU&7Dex`rCX5!D$#;MHrp9ngvs3NV z(Jtlr(kA7L&gy5Qvz%@UlmEL~?87)et618sV$sXe* z;Pw(xUP#w;&X?5tCyY%48m5mCP6P@Gp)a#GI#-#IQ@|QW4>D5BGb=;wsUqrEN&9Dj zpap@FnN&QYvhV|lGX$8_BtS$BdAeMNguxL~(b!_Z%u&S+i%BFx*>unPD?S$2*DJx_ zBSsbAQ#rUff+d{!YF~58B>CUSZF%XUGKt#KamDbSYsND3{A8?7Esp2AG zNQH7A0Aj}=WY$W$jot9G-7dGMTQ&9&LyuE2@54!EATt3wWlXs5CH&Z6#9+5G$9y&StAfTK3wYukV1FMKJuIi#t;oEx9(}PJNXvjP{1Sct zB21M^T2{Qy$r_(uH#6g*+cQH@dKuJMrTsNyaXvktryXnJkeFc;EqPa(gH$@XkI{7> zFHWRbnmi!fbeVh}r?$hxMGIqYwd<2?a#!wZi-aQ?DvqCLBv2C76>jq0(BGp}{FN)% z9Lc2n>RpLY7xA~!s9%_gU_bgH#e-WVjFAx=V599G(7$Zfan72=BG}15o7{FIS|GVZ zw?o8ybJ)k&bnQ;-?Nw@b*5Zc3&;d$}lj$xBn+UHXO4j!b{D)JuZA+U!#}>UJrl#Iq z^opABFD+zoMfibNu{^DXPs{ZhzCldeiX(Swy~dACHpGn*>Y{#C9d5nm63!~DF`)~6 z7$_}ew%Hgyu5#PGRAF=_c5oWvlUb(se~WTrlDV9}-!8edvRvPOw^+fJpQNX@I;4d;@hB8r_GH|kb`rbaNOlxYkju&n?HLOAz7ipGLG=w)-TI- z+Gy^7dIi$nUs*jd9aHJdznPL)T7AA0|1S5tWHYgl`vgbuchJ+8B*vx(W%*(dX89=$ z+nr8RPzU^vwyuY>-N+x5{YKs!;S-Xf(**2aBWX#4Rum#qhg+?};rpzy9+rddoPJkq zh&&-{4zNEV_h{=}P>Vc{^xKOAJW?Id1P2MX{k{5)0_9;;7}ihjB1!K;Ah15kAfIq$ z8cp{zL{3ODYkj|R%m{sjNr;)f7)XdSSwqb7Imp-!DXPL2W9e|0-*W^%(Qh?2z1wND z$aebN60#vrIY79Rc30mhqx<#V>{LxTcFPRAzIX(WOu%_!Q-Y{f_7TXV8<1eX1@)L2 zlBrRAj7FZ7ma=P~lny%y2e2uhjx0t~;l4=4p_|YAoE`K%~4|8_|_UH@QmA; z4A?OKDoyDPn=V#bENBA)$RWEgqowtZs|9V{%!~KdxdTqP#V4&++47e=>8>PUw?Y-X)ih(W|EUoR1=VloSw}@k1E@_!H7XY=gNVQLrXFsrN zj^BrqO)0t5J~OU~I)6WPvR3b5SE9C(uAb+2McnN?T}(tEBk_@p-IPr27ZwN*W5Jzt zS6kD2x5ij0GXHyS;I9no-w%;pkp5^V&bUw~~IQC_Heun-|0+ z@UT=@xQ$I*J4COfOs!Jqd3dRfhN>$;Ws=+#J^Wv7kKl03$Ut7I^tnmnyN)bk+5zEdcy71;+=TBl$Iv6y6%JvK?OVmSDj zps$XciK)G@LUy#R!+bns_~QVDc9d0)OL5F=xpCGVvgql0M!rtIxI&zo*b z?_DaZs@|B@w90By6oex{V|?82tMDUwne^jRG;$Vet@H@?o)}7gF!A!`SEEEW{2y&__!N5?`ZIoZ4d>NY4S}RhMpRYuqsQiWO>EM4&A((2y z2g4cKayA#cJMw3>;By;-Ou`2{YilIEdV54X3AvyRuFb&s|j(jIUZp;K!qr$ShVHEEmqJ%FAyDDDL74BTV(e;m-VjCjaU-4~7Hf$rDWC_@O)67v+v*0YY+or8R+&*&-(Y?`{`7N{?B;GB2qJ07!sRX~(lCSXpEityy_TU;=0zL#uA z=3r9(!qHbv!{%Q=WeUjWQgU`a2^Y^{Kc%MXlKlo~lrg+w!P*bcgv<>YrgZO0H4@2bol<#8GDj zWqeh5*L$j8MnF7gbW{Z%0+qcV`+;`+K6Efu_}+Amco@C3j%2hXkxHWi!{iGH)Znn} zXgS^=-TIaIf^vBg76uvZ3pV#D_CCQj@7@rV~LO6lino`n%79k_>;VvBb>@YetnyjB#8#L4k zl9EmE-`J|@%c&8v-Y*Sf{;*BF9Ph~=1!?V5utRU3Me|BqazIe0tws=t zxE*ImGl{U7Y-tUpF$7EgIF1_7VF{B{^!ju`&65jjA<9T?pv{QC5Q<2Z4^=5LY zPJBc@my|5X7=l?Drt}^MkuG3tG~{c2FAt|Tz7^*pQAx#C2Q;94tYX3v6;zRMI<%9l z`Se-n%Q_+>(n@7-fSJ6!gOStaBMs@7AP@63iJ+eR*C>N+y2~R~6Y+x8E)0hGc}r_6 za(V59A2wyYiSo<%SA^YeW56~qyRT2N>;vmecjTzLWg{h7Px#P!Gsk2S4;h`4$~e8f#+t`rnHY8 z{O8#)fdP-c9Y-ugIg-QA-FkC-Kq>Iu;^Ub$kLP_9sOc{3C8>93Sk54^)r`bP3E4W1 zTyp6NP2DEfl(52d7>6Vl9EbeADkHyOw^+@oU>G=Yt)sgr8p=5D34A_g2Qm1s2;l&} z0Ppg6nTST#&gS+UpyzxFjXH~{I^VKTeYTt!+GO-cSmUS)PpPAc-fT_wb8-oi*4Do0 zch~bFdGfppmw^B-myQe^M?mjqZM1fVClMTdZmNn!n9~!o6IaUjdP$s`mw5JdhPYGk z#Z(Y3bH0J@yQ!V;s*NwDKeJOllg*KD`>wOxg^92mFLe9HeyxUcW@fOp3H%l%GyW4~ zl_-_LfM$BTzZ(OiYnZdcWc{c@H`o{ET-n2uZf>UgjNXrdQYJ96*Hb*~3 z1wMGsl^fv2*#@S@EfA<0-#ylbcmW)a>g+y z-cyCLOIDux3w3@CI9Q_vK+!Ag`4p~hwX0+aPBoi~jnL_KTK5aY*zu@z0v_usP`PC| z3BOlF(XbF=i{}w)$J5Io^uBl^vQ$Qc3h#+R*FTe?qhOH`n{?B_#*X?F9)EyUSFVeL zHB39(&2l$wRyP>lM9_7{IzzIeKHx`-^($$;7OToNskse3-x5}P8q{OXCyA*GvI(PY z?FQ$~!um#Z)`88}ApS+X>%wEevm7PiYXrkr`XP0EjJS(+e(?{PGi2ItOdmNSd0&V6 zo!&u+LgdkSTXw}37+nb?fmLzbD&rn}g0YGCLSk6f8^&?1CRhsZM%MD2s3lDhxte3mQdh2Y?G+Vwx@;MEBeu|U`c(Y7H-j77jTUTh9 z2;(w~Rdqa!Ee}NxeYTVN1!ThN66aD>2Rf}{O%t&Fw_}7E!d9ZM;-0gAiUc_eNV^3z zIR8k354!|#G4?-D#z#%#r;elKWs{I zNh3v+yhzQi2;x!B5wZ}coVRCnx$mK4k2loiGMvX7&3v)NK=@^M%&3Yr`x`$zk1#H$ z=q-U@zrUey6bA<%YjWU^GFOfvSQ(?8{5i$kU5!K|Pe=HvG`t76w2J8l!uf>$ga-8W z@bKQb$HlAVDC>)t>_$rK3GDI+J(QeK*l_lmY*Y(j8JEPtbDE4hM_b#f^B(TyP?0XY zC1DsxU3<5d`B{(5|=N2C!# zi4k^-?%9%cOs{kCIc%jsiaK7X{03roQ@95HrW8N1aH^2aK_-F@rjM-U*dPnMAkScy zAT26+ZKF)L*k1g9PD}p(RxWHvL13&H;z4|n?xsOx3o`Zh=l;yw+tKQONbD)Loa|5i2$It?D~_@{^}E3 z%P4^tn}@C}Xwi=Uj_=_+vxc-9SOIT)Vj%39Rg7f|5`tad!ZhW;=|&N|X0t z0%Duap2pYwg8MxTb_$-mJN0>-W#g zW-m0ID*8ZLj1GBRlI<5yqaARTe-+5!L>InE!t{gSNI=-rf80IQ?JB^)pr;dH!Z|xY zjg=NHj-Ik>$Jg%G?HH3rs7qu`&kQE6U|&+_H<2Ow#=_ShIMpim2%yVuv8jzB@8e%T z+KS%Gi)B5xw$*xpXc1TJ!^l)Q(74nqj@cI1v0`C)jMsv}rdQc?P2J5&x72T+4Lz0Dzr@u$P5t{dd!l^3 z83I0RL@_-zBAAY>#}MxAH^MsCD% zU$eP6&MW-<*~VNLbQspj2^XiqVFGWON8hfzAxjTV3qiC;lqs&%NL_6d`OZ9J=GvnA z^Q#W5N*BWO)k31;zH^P%uWQn<=J}NfJ@qqd9Mr{f(VtK85J27TG#n90fq`s=pfdI2 z)-xpnZqG7+mG+5fDJp%tSHhN-Cis0i!^P0$HrR`rOahHIUbgvXe!K#bpUdGqIt%=( z5Q^~N%UP^SjHa^+2b=ko1t(gJ-As?G=RbvH*<8(hUzlq;EX%L zyVd^Zg8%g^Ar9dcZ0&BfxEwm-P1D2)f=Jf;-7nqag`K@3X^-7JD&UV$f%Ji$K>iVS zSC7W$;+=nd=(*(Q7G{`>;LOY{)39SE&5<3U!*|0UXx#KRijyd!wqmNt6awR~H9qEK z?_jgbI(>Bm3z>+0LS+1F>)oTDjiwn@S=F0Z6lKTF=HNE6awfsdepofMKdr}NtN zCT=4%y2~Bw@BihCo%PnU!>)Chgnuvr&NDqedF3Hi`M|(qezWQLc(Y~3o{hsDht2g+ zQiMSe&y84#@Ma(EYu_=Z(J2pkkb1Wq_g}{L$G3|RQm`NlK=2h+pK)7`yt!5^50&ll zM4y!$fY^8$6=Y#tX(8po~C85&jF23g)QrTC4r9qLJf z5XS>!S`-*yX=J$J3m7$Rb+v^R_Hy~$G=FWlrS^E?j(&`wA03=*M0_Wxe3m&zY$f&L zgVVr|MSUl!wDml9xY2D^_*XFE#+~TSj0N>6Z3CSL)}a_>&ySwdv~WmZ>@78Hgkl6> zoe<&8JQwBgT&ZJvsjz6E0Lf;O+fVvh8EJ4QH8Q>L>6M75xtfi=<^xGvrTO}i^h)2; zX!AV#7OGX@{+O25Y5EU-XN+);5+W)R*smo~SIhr?qTu}poeR+j(GqU9`1qwWRqrH` z$jOEA5au5Ro0Q)Gn&9K+11232C{a6NJc%$9bH{lSQ1zC6z^E5puKWULnJKtgu#4&2 zDu&fW%%z5mj^liqG*HT~BVi=Ck}EU&pgoRsbQ&_k81l!qyeAFOyiNcns%y{u zKGbJhdf9M>nS0J#X0N|RxmI#XN?Rv#&}xx#uRg5&a~q#wsKAzay=ev4U1@vHqBnA( zBV2JY;d z_5Kxd9h#HdP^?(*$KLpY-ybZH7O9lFikydYb z=o1ls!WnTV|LJ;#7{-2aimT@2wWy#~M^Rk2xcXR(O(H7~($sZ0JATBZzkKx1Z!+~& zJT;c^Q=2?n&4~uMMf~{Qqtm~-^;#Nl@uk$3{hxFAw`&AQkUtDU9O=7Mtquojmt_R= zwncD=>RLJ;;-3(NH*adldM=%U?uY=+oi9mk=NAv-k*LEL!xd>o@~H#mkPeN(6WUyF zvD|=5o!2714CL8CG=Uk)J~~Y+0Cua!^GNp_e3Qb_X>&8*VwK5z0FEBbvK2UI6MB`N z?-kO0K>h2;V!9i$*^9gbq+Xwb9_E8m&UVKJAJ7EIv1k+$Iv#K5t5rH93rsfgbgyv# z+CySkReFL|(D?NWZQvyS+lKyMzd}kQJITpA1jX{{_YW|BK2YPCM%iQ*aJ;@9zXiabE4qNuEO618kG>2YU_~uhh13v5)02b1jNyVoA2E)2yF3q)_QBxmQ7D9~?<@}RFS&|% zcq?nyt51*Mjr(PG){cxmXTVEPW8Ji!>eNY*EF4u@KAb((+(HHi_ruCdv~u;q1O{C3 z{Xp-9rN6xBzc1iF&cx22;=tBBjcxah#faT$e+u1kIt&*IMKk5b4xMDPJUFA<$Vtgz zoSBM4CJ(7~b)DhxO|Tqv$q8(hjk}^F4-^foSgA4%FVnA9Xg`hZ&?<+De1_Zhk^!0v zYq+J1ElILAzo zjvkW@1xo!b-oW1RV@iL{#J1(F^JSvl=;$bv5cJdLaYgS{CzPGN7QNqOC*>f_&DG~F z_x>a2&Xt^sPByqLS@3Of^0+~CZ}0^~A|NA@o;Qg|vgY@f&J)5ep?f>9q6+jubi052 zvO{9>FZ!$z$X$>CMLXN^;lpThtFL2;hyKWEtPD`S*sS zn1fU}Y~CI+FQO$N@3nT-2NIANCioSP1FQ1Br$BADXR9C`hC}AZ((CfI>42Xlyo2vD z8~Fsb$sqXO@W&WIKN+D=@Fr*Q+bDvM+^89PH+d&}^@WY8yw#5awJ)DFU(*l2TwjAh zd=5wMnjtUaFQktcM$L}=b%lcag1$W^o?r0qTa4Qn%%hpbqu8vQGdmRvh5cw*s_I zVSS!`9qNxEKq+|O%=QxlW+j~kq=arKm=VFM}oq=U?W3zeSdIP-*nN=K|0x3C`?-` z`pP@ZzY1|gKgo3y$~lY=yCZGpnP@}4J^WRR+Yavi0f%tMlvxZ;I)NKo!+v^Aq&@}D zZn95)hNVD~#}K1-KPW_6eKof;du%pzZ9QnhdUDl03!bXyZcj}UmV5CMe0==!is{Mw zY|JAdH2rPHZpdpr7WgUrkm2(H-!x*#t6NTk^~|;D9;2fpl-*4mr$i6??~daXuYBLha% zHbYMimqVt&<5s^&NpeX@A$fbP3RhkB!=tCodmE3#@8HW!&eGZ4da{~U=n(xob@ev@ z15v7tTJaEC;I;Vc&NE~r^Iqr<%e)XwdwWYSo3{F%&wBzi`2954?{9YV`ZrWwlS%p&;u;_C}l0`WH^D~e3Z6FB;L5s!wpAi z<_9x`LKxT$W`(XKZzlsUh@}^`m)G-)^Gi>>hGMtD_MLA@Aw2GplFF`Lf3<}I(fFVxH1Tp`7ETBwmfrVUTy ze5Uvox1ON7HC~)T()?^dVr54Z!a>vFW7hg2v18EPrMY8pM#9m~ZoVvF;>GwlbAoif z#sh$|k4(zRfiqf(FP-xU2oM}tH_4Q}dgtxxyW{?y#z(T3Wiax^%?GT0kvCp4UzIQB zE_D4`$P&NhOK$QP-mLqd*`@=6QXP*MmD|7>L%tN?x;G(uff9Ik)BxDn30%S@!Mk-8 zTA&0+4XOyD^6~MRAg)XUG#BNeS3yr#a`wsE(C%gY#X3!#qO1w~vz_0e}dM3DWe0cb!YF_!*^@Cr(cBF-GDSo+%egDq% zc5$@TYP4Bt&Hs#Zh9WrAedzXL=0%VcXFU*jQ+mBm&tnaE3mRKbmW;-e>pgM3S-Wa4 z)!n5YX|VSJIM>?@PX{A2u3wVfR~;@lybQZHduL$4*yPjnJ*UHRbhO6fKr_3v*K88U zDSYw~NDMkT-#=RlR;th2!oOAozM8%f|RuE&=`EF$!X+LwqMgN({}By7Ju>!1m|1&)_u3pE11!*80*aNCFjF$i+_Uozot$GouGT3% z=NI3xd=ZhIi{LRp8v<$TZTo|c5T3P2m*qNG|151-AYIb0@B?*w6v5+cS(0kNq5Z<(jXz- z-7w_0(ffX%=lzcN`}6(cm|=#4y{~Jp>s;$R*SUV!{jX}lAF%R22qvl=Ete1Gm8b6y zf2uFdKRcUS`AqXS`H!OL7L!v`a{>H;JAmO*ygfsYYP5T&<3+N9l2>0ZU0bK6r8WQU z7ge>@aTR+T%9=dca$X))|1`=iJXQSM++5rdb%)%Lqh;Xu2Vkv%uB4+Sv81=yuN4aR z7Td@+1~*IcUEyn5`4r^{ut)`wR$AqGdTA`=vzy~n)@U6UTU%J|yzw}@9Ha568^m6X z4_^V=RVA||jlMPB+7^6fZE~Z&h}i!AcgKF#G&3YmIft=q>>={4?l%`C>|WQLT&cqD zCm^aaD=RC}noatSpH61_JGY&Irz5$SCHedV^uF$=U%xI}irf<2agME2?@`G-m1>W-)jdbEd)Qyh9#Tqv5O0;h^_BCQ#LSd?1kd`kua{n8 zheWNJ`VWQ&00OdS?3x|n{#P3;6%2_TyuU(l$QRt@4SX>D!~#SU&Fb(l1h3pqXEqS9 znUO{VN!@p-gD~Eny%3F)^YnlQHW|rJ9Dd?>f$k(#e<9F7ZI5Ke&Q}knlV$eXIq=2E$+E4z!(hIo^nky4nEzL|aKUaS7_f950qyty6O&h^fFwbxz}b9NyZ zn*=3GKu6beo5})_?(Sru0^)L2SRPcdJ*Acca#cw=OC4%KNfLDp`Rz{ZM3hvX*YK7r zugFiHV*_L@^L)IUzpOw7ui4+bokCXFGqjo(aOYJ2IZu$0KdPmvY0N8^VrFK>;I6=) zDm*~&5lcRvql^qx%Y!)J`E8H2HX?MMkcjAg0r#6MQ~qWTD`65#{*{} zKR&$dTI7S=;C!)V7S7B7TXw}>nQF$I0ayCIZ7Gh)a*&}LMD&(!9)5)L zXyn}N9EeNY`lDUbjIy@LR2ca3u?~1avT7~@n#4HE*0=G`jY((6*i9lk++s+xDlrfv z;4<`3Jck8D_rz|RY8xaJ$l7RwT{GfyZhrc2F~?ZbDdTM>-{yC&ggFw#hFr-F96CSv zkM$gr1l^l`eolb%nqY-5?%5m`2qZqno;fL#qG)0j=XVop{s#WE*LZU^wm|93|A3XG=Rw8mp=g8F3|(2?i}-&aOsB~DlW#4 z$Mtn)3Gqkq4PC^^i=S}l=`^eP@-gnG`Ot;30^@O_o9;zoT(WcrvYHMK8SgH^Pc*tO zy@=*f1+)11W>cy_FKNZ-Ti3SoK-6%`dGCUZD>H;taYoI{*jt&O6l2Fo!`IczB!JQ}f8h95B6}p_y={^S19GU`y zY=QJE)2<=O)VA_xt|>o9c2M3oIdq{kZ1)na%le!YoB+$oj?KCS?7J<|)^t zEv(6I@I@;{yV-$uaxgOd#H?wvd2+e+Aul4~B1ClHH}>gXb@V|F zwh$vr>s7X8NJafJ3f0sDEaP4Sy1%LCsUaNHgQk)d-nO4+QyhPPKWE!lb_6~2z7eo6 zw?w(Uh?WbT>Iz^*LV@$cjNH5EHwEbWG=lHGer4Z562d1(n#mqrNKksa*a-4jOugU$ zeS{X3%x4ij66KRY1m>3E>>@TQD|0VwMpqTxselSW6bjnWGUkc~HEgILK4qTOH9h3e zSuHDWZCzIEz}O<#Bx!p3Fiu;q)i?-@6MS5iWg=&Ve$~!l@mg&0sh2FSOqoT}TTtp7 zu$bYyc2enVu>mvEkQLvW*?>Y&h)K*7f^1Q0YQ*ClVtUzZ4RW^F{PDY^;!f&?&4DOS zz4EK7s+xT}>u!XBBd?qvK+Rdd@O681CjPwc*)IXRw*S`|Axe)k!e){fmffOgH+*BV zccAP9ZO8gsj>UOIjWakdX(M}|_P7$fDuhx$;1+QX4=G{TtR4D1+?*VBk;RMLud+ah zD%vOxtvyg@RY=&K32(I)>oq0A38?@DOO(8wjdJWdNRM&@S2e(m&#jDdsRm~_U4RDY zB3O)fcAfXzSAezucI}FD!|Feb>XM4+4|-bBUo>vUDn=5uspkft-zKnry*{uW6wfeu z=89M|r03=AZ@pM40kz1$j-4X6-opNtSIo%P{S@7fC%LapK|!&x#pANm^$K(a(=FXb zfN!%7$~c|Qx;rS?c0%~Pbn@k3T=4op$YWXM7Dq1QfsZw_;*6TlB(QaJTD%JjdCF*?dhblu<0>-7BpGh*Rr-rbQt9spqU=~$|#NC zA64=?a+#`<#NHC~uAmtHG4Ed2ddlevA-A$#e`NTN0_5-qNm`9hIygu>CAki@85c?z z6WnEc2evsj*VZ~hk51FV@dLSSM9)l?gxVjj3R(|eTrM=f8ShJovnR#rd^TL!aPE__ zPQ!>emj47uSpBxB7^PBvV^2{Lb_!{gf-~nx8p*SX$S=fnyc%fxDcjwpTAB!lIxaB% zIs)J_^o8d@tu1=O)30KvU``xnjHJZ+tlDWYc%5Ce4cam09Pe38^rc@88;=Xn;XYVh zQj!WZk-Zm;>F8XDq>Y%;eOoE*GCW)2h7{{Awd(k84{{(SXe)8)U7zB<|EUJ`xt34G zMc9jQ0-~;qzuOMU53tiix0owda^({aFrGat0;3o^aB#)5U8ya4A4ji5*4#N6qq6Xp zS!bjkb#mcWbJ_?yZpdlW?obnOf#cRBR#RHb`RLSCRhj0N5It`$_LWt1o+8X9OBDE6 z@_aC%W_zpbh30;eVM)v36E(To8;*bdl!Z3aZePyA$|?|cG!DiBKxRP;D|kYhK*aXj z^*FVd9^&F^fnr7iPPV)yUS(B#y~xU5S)?0xL_OGbgMQpc>|$Gy9SDd8`@9;P z_qjH2<-eB%`Eu{jGTqAJVt2dHR=@2JGJ}%c>ACiQqw0ALW5R`4`fk*b*$AeKSvI~d z7nYs<%<8r0Vu4&*_9y32KwFwok2kq|J8?+qVlb}(=0EM8eoxEf%vZHOByrNuApmO1 zQTEL8OcEKEpgIyZ7oo1auE&kNdFkpNd&4A6Z>*oC%P?XG--%8eOe34^o-2-$kQPQP zvG1+@HBcgXQviX&!qPUnF$e`&{)WJT=WuMoA#oo_|3#6SU2DyrNrR07!W{6)j))nr zAj3nk&GXht51S~vsGrJih_4ONS5MfTGI)mbPxjxT^2r5lwQw^Mzufjkq>=$%qIig8 zqt&-Kxlz-~@IwsP-(+BQ8Jahf?X8Z+*rL{l!D;{aQHR{_B}#|f?;=*8=IkYEPoK0I zd5G=eg|Jc~nelw?4{MV7fR;YYM^T44RJl|QpvBu*#Mfp1gwRe zBuaI=+@qG~8?n>KyGl&P^DVVqc)w$v<+a?$t7prQOLBd&!JP5dwF;?H3KI9RX&T}x#&fQ`%1hmDOi%tHgiANxMR)l zwoku-ysiTBONxqA+2?w|iG~l#r2S=8eYzuF?`F>_-DN-m20+#+K?u*OM%dYQD<&`? z$%k>;yh#j|K z03Yv`sxEW!|N&(&&gZI^u;x-QEUpThvL_!Ep%Ca_`JN;HzBLg_>(PN{Z z)@G(3OdN~Bg$_V_9r86r2HHQjLx30%#_T9Ob8)~va|r|gS#rBXgXQnisKkGFz%Kx` zx9{h5afr!`iDAW3TsysbDY1FCG_QsFT=DbKh%EbO(MIjTJ&2n9XzIWl+cL?`vA*HXK;4%6cNJf_M# zryeP@REXi5FpETs&vVa~o`ZlavP(>4?OmgrnezF7j6e+EF>gJ(4Nsob<`T(Be|dRP z?90;nYzD`I+MjxmxfX~4yiP0glS_`yjnM}E_Egq2n|3bj9OkO-Db62-zwUnV&L6sq z2dxJfskmSOK*4_hHQW@v#2h@C_wo~jMI=o`DAd2Vq$2QB*{pV3T6PZx+{ z%s;V^plLH9F+Z4^BSvlr z2e`C}26a67XrNo30>eg{Wjp>A&@+$})h#*jPAKr#@H<6^PYSROC7 z7d}8mVKE)Alhs6CrWzXqoQ{h~wrlr+l;!vDmtD(A#jbG;RHxRnK=F1N=ga+LVQn#z zHXquYgXkslu@!^jh>l?AAbv_8W0YpdA36K;t!KS}jW6;HwYi^^Rk5u+4CgOrw)BJ| zYGaKjb@)ncB>AD&f-0@WV&RI{tFNDHcukR=qj~~?R=(TeZA`*oh#w{n1MR?g)P^y; zyKbb%)6Egt=rD&o>Zzy-Jo0kS!`0;>tBENdh{~`aqT_J^)hpqmbFmf@FmtSJ6&Pj- z((Yk7r}<4$gKCKP26D*zzEPxJ4(O}DlsPX&^=5g$7Xy&Jm^Mh#p4I5Dlc%9QN@>E3 zTYj=3`D%1W64hK7>I4*H(!Jat6Z<5MR);jw+}KwY=2)VEcsZb?;C@&;uaEU-+cQTij{to5vnfi6Zf`$16@W%wcL zb$aP?o(|+lHg<2n?kuR?mtv__k3w*jK>33}wI#l0O)wZz>!VNhjw zuNt~W!HXVr_?RvwD$pef$9ESzv+Km1$<`q6H~Urzy3Gf|c$J&dQ!4%dWx|A2#(G?O ze#+iqXPpAswx5SMxY6L^PgCCLP@cQY&xOg_ZSST0;p0Vp_am&lIyKA9jW|Y0o!b*f zjwPgW!F$pcW&`0D0!Rb+!b$gGDBO_BaPXctXTrg;vUs?5qUYWSPW=UVi z)A%Fy$Od8#(h%^`N))eUGKK_wfQ-BdHus5daBO%(4#%K;O$yS|%|5Sj3KHGHS&9me zbky}u|DdM!&ftACC)ZS0o;pddAJY~YvXeE@n1-ZN1oLURo-MoJjH2{359c#bOgu%h ziAv=OHG>qtKCnf8-F*>ObrBiEz-S@^9zwKwA*+h)FTWnS6U?>1 zYFR}GeZCu{Z~CiK58cI>xFOu}V{~qrtJ{YGU_=|eFkOhuT*imnFWM&*$2*@ft{rw9 zx=GV$_bTObRYA?-p9V|%i1$AK`OE09+g~OVh4WN1?Zo|<@@+ofanbm`#tmis>9=^u z=sdcFF=`kbx?8()T@sq~>+AVg{v}ujqfR79w2=Z10}a&V@8`+q+W7urUpN%rocU+g zKmk(y&Hd%|e1TTlrzn~i6*Q+un!%)Bx6hsUAtNQe>c@us`lD%>pL}3X(eyyieqpJL zzQpv)@`bw**}0&ik)qE$*7^9cFl7OsMQu002nR1pp|*Dy<9uP|m}^@|lD7%ezB^2K zLK+&fL5)X!1ZIesU8!t(W>)d#_BWZ_yfaqURqS!Q%J!6gWVpcx3 zp1pb2Kq8|tpwA4f%g1~K3=a|Fbm&S{u^ER3pYpLBXk53FY>9EV9)@zl@Iew?lwz1H zz*$m>k*bGES=c(s(wm2iYjkkRYiu6fRA17*22qR-Y{^&cYUgA-@3f!n1 zrJ2+70@H4H(t;KSXuMavvJ@o!V8BS{wezmjkc$If!R6A;6Vj5| zrgG8hDyi$?p2(=-k+!D#{0mDCqHrMpGU|N8cYB0Pk2Jq>-dn@QqDI}uIbAloxcMq} zB;_DD{H(X6dVBV597G#7j%%GoC^J9KzkK7L0X3xM)weTeC|cl#=L@AsuXu;XxxG{W zP_>;bTjkE$auN7V8vRaQ4drDDmV0g}ruvGveI;Xo{#7}kE~)*Jo3e=h+d&p658)$t zn(?kNFfqlB#VFT2?1S&c<2iY13o}`T32e8v5`3HPeC9NQ@RRs2ehG-+v>`G{Rjt#c zE_4a1!rWj~*8(G8kd}AVw$QwCd}N|t_J2OW^#At*MKKZ{-%>P!YHDxtt__(Oxvz8U zb6?#}DIa%%jRbyjyt9lW!YixH1AwSsR+y+}>|!F3_Gu$`{#}DaWeBr|S`YQK)rQR1 z0RJZ|(Q9|iqXX;351+WU%a&TZx0zc0%6^tCDVJ(Ht>b09np^~k#+x)&g1Hwt+U8%M zmyxi0^spAadQX9jj9ibRGII9xXQr&7GYLIb(!!h@8{t*RQUBNUS|JJYaGZ9;;sKF3 zq{9#659jA)%3d4Udkfy;F8lT5xQw0EdcN=`2{ArrPfCV=T=>O!cCu_sonxnhWL*QP zs3cxmc&-|lpW7)LmUiJ@xeyl> zvVk2oLi>88R8mU428?arxBQUyzPW>7kDtK7vsmZU{+h)2`z2*dI{M#$_U3Xdt4z89 zbGeeD&xon4Oj%uz1t34{M^y@6ennu7Bn1NlDR6$6J<>6vPo7D8oHW%nURcZzNwX1- zOx$Ij*QM|8pG8?EdVY!>DE~+4psj(VEgRmJw7&8NpDR^d?CPcEaO~{q(8(E|*4mQa z@?$1?)kYi=Vi388rWpGEG&M)zH*Lv4w1=+r*REssNuF#GZ(=d0AOvO`O_Co6!r~lX?L@6r6-J=0*nJ%CUUBs1_&zgQM%s_J_!W zwQ9%z6sZ7Z>&OcV{MU6gKcop5U%pt|>{3;feRGqFpqXgcZWoIV;2b`rv6NftSvrd= zLjp|BA8GyGuC6RBX{@24d7U5*_OO8=tbfXM# zyUlqv=qNRYMG0YD6IX(q0BJ3oONvBGK><toKh&PpEikw7^wWAh<-Ka==3_X?ui=5GSfs3E;ZxU;k0VoM;-M zH*@9ENlmhIKK>bfQJkY$$HT;2GECoWy`f<(16+2tKIw9qH6xj)ekI{>sNuQwzn9p4 zIF%!Zl|P)CAN_g-P>0$cXy&qH)AM~K+8(|i!%?3ifSN5%n$c1?&f(#Vi z=1JzXwW81U7?J>4S*?_}o{)7J2)Gd7>itT5MK4tX_qaWDHcQ9@UKpU|5+PKo*%=y# zwz5ci_q7`~1&O|bZ>1Qm>(*yO8Y6*kbcPNLtB71Uc|}VfU0D{y$d4$(M<1(#}uNXn~_Y#hWU%cxo7TC$@0(Le-(pv zwH)!)wx~+X+f3|qZg&+E+OL`ScuU)#v7UIe+xY?e@Q*$;3XBwYbxM7LJM=phPL8t$ zh_hn^@E)z>u!AJ)KlkAb+Yi&t(;{||v9V>#j(FKI4P?Z>53;9ob#5M$5QCv$)&B~dRu^lRq=IG9U>d6egWfmIJ{z7w4p_otr zt};BD{#n(qyX4qc>Auy?I#yeEQ@bO#+cOlOdIK#zs>ae{#ifx=mBPqZX z>kMkq@$WMJ&$9#+Hp6_Q7yV%e$$S6o%@*<~2$DX_%nX%;z7j>|_-c!^XTxp_s8%+p zJxa2@l|HYHzuHi^aGBG#AFxCFu zB0y>2?X#s1=InDXUi@U|K`JLk;15~@eZo#n7-Y`03Gx#{JRbIyZ`N)If`S!Tkgl@e zlEY;B=7}@rT^EH;PBTO(GGK!R=boMqAr3m3Kb*~QS_z8?h4I@Ox@!1%O=`5JKGm3_nqK_1;h#Rix= zUkXdrw3BODll=Y0u3ju(wJAbs`fj_Gc*a(XO&qG)R)*UO%}IN(Fzs7p_pybkC)p`p zD$zi1-T*M|RRlVls=lg?Lj=7@@-7kY{uKDH7r?bP>Tx*#`kJXM^AFD}SL~}fQD3wE zvu%}iBA-j1l^hgzJMfu{{J`pjW5I_AV!Dj0ZkjbfXQu{>BT#n+Tj6*4{)+tf<^kXq z6F%}vK_e(3`p=2EYq;?%{Rc-U*Xt5P?35{X1B``;ukckp+>#4HQA?g{0@a;xDhT<(R(G9-Drvt zIy9id$Uq-7&?s;a1^C!*Id60{w^S9fmAmI0bQd-^YXdg>?_n2pZDsjC{X4MM0(;;} ztzL2bF0j^geFyP^1o6%b&IoP4o;DB{#vno(m(_5?avPd?-&g)@={>}H_`kOIKga1) zgx0XVu{HwEv6M{U###rHq^e$-6=dvh1{W^Dvq?GG>VG+^{u zdBA2MhU&XGdWRWG-i0R8h`=r)+j_C`Ht(W|>FIaqa!z%fYnQ+XGLu(m)3rQ{rTO0# zzX@jL?hfvnLVvq1GT|39L+V;#Ov#)U*mjS@ev;j(qQfl? zv!CKxGuR>gCOb9TCzX+2a-`mC2FVC3muJc2V`KA}V=Z#6S3NBKN6TI7ju|(lr5e?e z5o99FwY9Y;BNEuqeTdckuS#0GDq^8e9}rk&gsZ^06O)tgy=WXHv#9Fvt2bzm5sVZm(&fP@nTh0js?cJ5X}SE(k2ODb`v!ojY5o0lZ%Xo1;GVP zKj7BjC*`l(HNZBu+ZN+UvdT8Xx_7J{d& zrxhFsN1l$()d_et@b>a}Luy4A7OFIMC{ESyZyAayGBOfb0QxO~SkPXyN=%eRqgnd6 z;c&sjWN&K}{1QAy3`=vJr;8N4jfzW%Gpy`<)sqSLhJUy&TQ~zYQDCwiLj_(tGO)0) z6my^GXNhvITP)9oSwa-5&$_FhUe@8|PY1)FsB$z!b{imp{8$Z*&!=vjvp{AI)4vO`x7x`*i(O?@Dk@vjDGnJYO+U& z2LYHWr_T7;avTD8FuR)Z%b&o2QaR{VG$q4&sNQvU%;*`af?+z$`tpa?yR0vq?*7OznWLf;~Qpdsg*!Z#YrNRG(H4~!QgLG?MJ#f~}dr!1cLrym91=T|u# z!yS4>-gn6(-V$08lotORuYpW%Yc_b~#pgY~Pg+j~s!IPr_Ag?-++~b^K;eHa?Z4k? z$B`rll<8CP{F8QPfcISP&I+`}JNrDd)o|+FI0Q*_y9H~eIKjIjmrvhE$VdoQ_@5Zsjh#Kj8HaUQRr{ge{ z3+BFLgAG62Vowg{Z=4lmR^CRViZCh)!E$SA>maL8716ab@2Ha<6V5wsO_R{V7IY;H80)4&*1pI?i2mxquaHgmaPz{MKtbgOm* zt-_!C27^VAM!>a|K_F{J-Y|)9mnS^U&jgd6EmC!lz&gd%g;o zCBSd)7nuljcd!A?EQt1yAiJ}h4^3WdoHYgi*Yi1u-SRN48U|`7Y zSIWJvokg0=p8Hckm_8mG=6#%pZ_?K!Ao^n%CFD2y=O%5_pWi4Bn@_ntD<0%(m(>^C zV&^YAZob1A1U}A)80lt--xd4*knwQ(P#kg*O=(a}azFjB!l0KBTc7}ag){5(Fl1*q zDo*i|anRrN4g`yQxN>#Jt9q|;?|~^u$rUC5__BN3KTEzk2x1lu|aLFK4FAcWZud`ER?X0Z>WR3~B2=q|Kk0)X_QP7nn(LOpu z#)oeuUovTy5+3jB&A`bYU@Q%5Br2@&kj@?$nEbz^J??WQj zkl4{}j`fn96Edf@n4pCs5LG*L8u z1lYDr%Z%}K+41mPKX~5qEAdhYz;SqDt+A$56eUC_7Z9E6o1eZS2b$)( ziHY%IR!ulCi4sDG?Si?;6QIQ-Gh9f~R-;Mnv|#w)adHdz;qFqRx*6`iN!DanK+7P- zD>W`Yk)cDeGr1e=>|ARZ5&Ip>Dd5gYLN^8iw2Y{FPGAb|h#+guFsPMAx!@cCHn#zo z=2fpTt3i7=EZ`Za?ii@>5+-z?W-)5(_DkeTlWI`UT+`s8YRLyC{F5 z=&tpomq^TZ6RKhEn$hKDLZx1z8IFvzYCM?4R<*H_numM&Edl=jIvZJkJ!2g@?C?gF z_x?}$<-b>Pi5-nsIia;mf>lCT9w;H13~bby-25PUmk<+{$9z0wH6?!I5p6wx)ySv; zZt*-#eURm97#IkaWq|1QLLrbCn>kmAl<+M%+DY=Gia+jP&@=e+mn^~_kO@cT8`_s;qVu(O)v`B+TvNo;@sQo|rV_IwjB(H(_ z=&vsq94kCGsxwqFwtC+797TI;M-cO&oHUUb-#VCgnhgN+0v7uLTe~vvwrJ#+PkaNg zokVj4rB3@HM|AG@w~j23A@Z7s&FPJta?m2ja;PUT^`S~Nl0oW2f1|T2WV-Esx==jm zxdcaZc{wS#Xyp0)Uk>em2Sxvvf0SL?l-7SjsUL$c92Y8YQCE9DwJAH5KQ#j4*tS)? z2@iAB4#qj_?li48tvJ#wZ*-Rog}JZ3IK+beqsrUo|2Dz@53uEkO- zCU_>T<#Tgz4PcY|5Nx8SOJ^^FjHU-CwWV_2_81VYG#p);FwtgkO%tXE^ zYy8F}@A|sj58KXCC(_^LmQ`OonU>|waJo?BB)VQ$^Wt!^Lb%RC&2wkMqF7#6)fpaC z$06V92?NhGIO2b~l8jGvrXWZ|#akQCmq%7p-JwaNh5`|y#2Fd{b+YWOZZ;xsFWUbZ z_{4EzP)%gp<8og`<$!bdo_o!dJWC;CCrr_2JMTzH*kR=j&OPOai=ZHso&e1&V%2b8 z?weew3gGvkT?^aJXleP)!ZcJ?I1WD)+ucmm71(FMih3B)m3WS7Bt(?ogJ5{`pY1U6 z0{)DGedNJl*l_-eZOiWE0FX}_z)%i!_ zW28@UuQoaX)7`SP^CiHq17#1&-=3}ti83E>x_l%{w-@OSb~|d_x*HjMhT+cOQi!oW z;vv0vrMSDpK2p_n>34I6_p^r7_LB%L_@jblPBnA7B>!87%RxL=MxyFV1&2ipw!{_{ zfY11!$IKraep+fI!q+&n4T#V9Pc0u%yq;VzxDB>@xnO8#h$)`mOKon2-5!vDnk<2@ z6-h1?rwW;Mg}lT?)WPDOk#phsd{QhkR+`#jb5$ifBw5$=Or3M_p!^fn8*fSu106$& zDckBuPz}jH%i|=`uJxXfMg6P^$EUS`QbEH7Mt$~t@+Z;X24H|_nH}_Z+7XMn_eTB% z=~W;?K>Q4svG~iZe%GN?NvH+!+xH1Ur_LCUun@glS9Rj!vQX*H_aXj_UAJ?h#O;m;%sA>DB(785YvAi+n@7-jPvD%Y7 z6@@YLGfSO1@=$nET)=4{CG*M+au~@Ei%1XeH1Su-DTp@-az-39T@jM>#l7Dx8|{pS z;kD+2JB>Ze3Yy3kguX&2_dog6k{`Bv|B=Z4IS}<}DU{GLg!aF;kB^LeY4xjq{(O!{ zpNxrY>XW(722l9@PKe~n7cD%XB;L7W2rP&MvR{dUH;Zo7o1u`=#W<{29wefHsOE13 z#1;BPD=c6I1#;Qj1eBki$D+D&9j2db;ZFY*f&=XZr0~~%P8~Or-9L^iZ(3A)WaqSq zn@s<1jwoF;UZ#Mv7-%jVQjCP}>aTL6nesj_y5%ua9Eh@Uce8YWB%039;5L&KvkQ|i zx{=07`E)EF%BZZ~@&x^u=yLPjFHeVs5*6Nj(p_)s+w`%%jTd#p#M%q|s!QvWwStnN z&-Y|-6W^0zHDg}m)QY^Pji7PWZe;kNt4-kYU!dFnsh>-|cEj#L)B094WtGJ^wV5A^ z7y2;$(4I!M@p5P23DAcsDG)J%R`=&yqWqNhs!+R#wyhGY=blDodJn}b*%EK=#$QmU zJ9XLJ@6b-&g}ia<;>KqIpTwjMU><~BwIZ?o(KQCOk4R+R*u7QML+g#$`3baaluG^y zZH*<|DYZ441PD;_cAhu>Qei7d!wsj)$91G{JY>?M>zUQ!KCC-%rVk_) z*em1&tx7RFRgZJoNrvP~2``s6#*Bn*yc~Cp4ng7?lS=3~di8#uO?fFL1ur;(o9a-e zbBpVs2g$}L3ah}V;w(;4u3y*1$Z>~ClP9q`u5!J}aUtFowgp`oEBKrx7&B*0C=C};0is{~-cPA_~lLCDsO5WYhQ1thgOQrNp+b41%& z>VCVV0^?m(EvC!ZjYPg{(h`lgvS68zrXN(jzNBo*uq?cEEWl0F~4to ze0-H*&l5T(hFHLR7^-F7t)-RXL41_IE6>sJCyQo9y8aADbJ|JN%GdhEPQo+TUal)n z=zRP)XJ%q6i-`vDKj8yj%=al@iWS#TaDvdpcGm`kX;?1f{_}URx6{mz%ZY1j>8Ai$ zN?wMeWMidZKGx>^%Y@)Jl+_L7c2$dUQ-4vqUvGKjwd#D?+TdEvV)yMj;!VR@&%TA{ zI7@ARN3yD|0iU+au}@mSvSS?lF`Wb&tVm8yp}}4^G8w9}#sh}m2gDzmDBG_*-bF$8Ea$>yQPW}UIoChQzT~dj9 zmJVLWD}n5;3)V$tMe)fTX8JhvCnp2D9wcuHy5!jj{#~?CxTfWwK9u;{CWg4I454_b zyy3DFJ1$z6F!mG+Z`a81G_J?vo;(fbi(HdFIOsXxR7w?#gl&)uS4D?*@>MuU2;rM- z#$(n1hePfF_+_5o9f>YCuoey6$L>CB*p?@yi<50^ zxHFXoe?T9qD@-^Uo7y(tj8lEcEGE3S)hfGX7_=G<*)aYRvs{XO9jc&kyB?A63=?oS z>Niwq{;9{}q@p-P6rGfwFBX4$u|jh+a566*U=AH^L1M1~{RhzKqq(64+^`dg`reGN zXjXa#T6%77Z1msX-K;lkrc222sBBOHLX5{19V2*rq@++{iK#nnXTJ15W5*0QcWt{N z0eowsh}7oc%Iq@MOiiHjJY{i*51T#^kHc0BoBj0|#Ie@{i4=jzF!DYQs#j=RnKk4h zikh05PCn0W6~c&k6m&iIxn^2C>VTel8C$>*!g#Vcb!`%8rpblksaD@6wq54|8JGmM zToR6mzQU$}N!33RlQTqkIk(S?nLl{&KO9qb$S7DY6{6sTMCpQ8FTY}x{+p@g@*tSc za@l9$_2Ew_WhPL2$K?)mE8yHrP*cGN@}=p{J)D)7$(W&mBH?a$qv6VoFT&j-Oq&V# zyF%Yym2b^;UIsOxy}SI}y?)b^u1wRr{tk23V@p@^lDYBMyZhIw)chubWa92w`f?9X zVD;c6KF7m}O5tsA>j25CQx5EezSp&$_c5iCBiriQX2ee+{&zy8Rk~smfqpgIM)e<~ z`cy^7%|1C|&Kc*MuLut$Qo*xOt?jBGv76i% zepFD1U_LNQ%}>**IJoPdc>NE&_=9`w=@4f3MfKL>&v$Dh>n;*fO-?t4PWGyYt0=R* zXf9^{-Wb+bIQ7MAbqJr;;-1p=nR87}f{$0;YP5Wc|0d)isq4OOV(u_4OWP*uaxjZt zO?YbZrpF$jL$C+q$fjjVP;I>j!2mDlL4HFYq7hu&YcZTtKF*#3UrL7nPj-uaQgoyTNng@)O;zw>3c zyH93U0$1K}8ix!D9DFPDLHsfX;@C?skfo~%Wdp+M!81zw^?8^hzd`|7pLMg;YG0)K zVg%RsbV06t9$Ft=q@4a7auU4@W=jVxY zAyJ}IqA7%_xvg2cK6A60stJts$_)NZ)vxO{1-@2_gjmJ&2}6WU2hHgi8Dl7=BEOKa z(-~CU3FF=^OCtY@(%u~1dLRFtJPx^mh1|R8Cxto1l>|rw^|}kQz$wvQNlp26Y=K<# zUa9pJ#1r4y7K0`XXBCwVq0bKvT6>aJQNe|0!QH;DGCGJ0C=^a7Jx$iv`yLPh2SMA&ZwPn=b{FSF(wdn%?3e zX5Ll78?b`JfL{y{@C2j-M$xZ(j~Rmx27g$)Ybm7h=WW)DdOy19_MP4!erl;Kdas$H zwFUrX{ytIh)GEbPVI82~xD;ctXjB2ggIBwxOv905zIYN+Y1Bu~^Tu~R&QHwe`%=0M zDz>zxVmrc3=Vt^9OUo&6!&SN%7bJSnDp*^%c|$YDWFW!coGj;RfA($LGP7HY9O?15 zCYFN=flX=Gp-3A05F1ScgRBwMO~4^Mmjnax^T&CaT^H@O#h)HH2|e*Y11dWhgf@sz z_BX8MkmmlJihre0Rw(fMmzj>f-p@R!_J}OVg3~C!jfXcK>~SH6sy?;>qp%>Tr`=xE zut;lec9?YojtOh~b&CmaLtjD=u>~_X`T_f%a_Uhsk6Q;i=D|n$9S?juTdS<<^*%*Q z3q*#fm?GSVrb#cFRHr{8KW;Wb>H`mg0W)x)tCdV|E&X_2(jpUJf0UY$!J;U19@l)e z5?b|Xh!A$wM;2dK*XrNY2VV?(AZm`RlzEg0O%o&Rg}COl1rH-|`c*k+kCFNQ;Mw@F zeHriN>@vz1@};56zFon1Q2_sLe_fd~=CLK_v5bz%if}EaM8I!B@lKjGu!xrPe&?_$ zM@NQ-j8jd3!yLUkT63Y!z?VV42cS}k;ajN=K@T0 z2p>aITJEOu%h6s#HM`Y@ocsRyG!-7k2u$HAnee+C&503adU}Lt?Sf62?8ws6IDkc` zWovaCHKh8k*NJc$6eKyxtXFRzJ?M9Fa=hA?RrWg*N$_;AGrPy#adT(oq9EP#iC4XE z#G+l(K6kQ^M}lR>^wcE1+L=IuS09#zt);Sfy`fuR%)#mAunPDNn0m=?FwnoP&9sXR zPCM8Bba&nu1=uo#kIm2L<~AuDAfWc2zOh+DUTr}39@MxtpLSsUj* zX*Z0q#=>>cx!@LXT2U@8EJ-h1^ad^xbw*aF4f;)BcIC&GO2)z-k=ki@A3Zp_kU)C5Y+E8M@S8}MJ$Kg*2l zWhCQl9nG)%aWzWOmrFJ4wx1FE0^4;0)s;#9(?7=|>9fqq2(;}S6&`-S)#M|}21&=Q zIf?p1+y~P(7Z$9eeSU6Z}*VUosH8(#u?cvBHRhzzASRc9NL$lR1ptR6Zbru5# z{Gq6u#DY*^Y|Q8;KMTMP0?_Tp?oW9!QJr)yZthOydC6opub|$nZEz6I5ZEy1f}_r| zUb&>AA~sd6tkbjI6Y~GCbyiVvXv@~dCAb8a#)Ah7ZUKV3ySuwPgb>`Vg9Qoh?ry=| z-KBAtzq5DFx%ZCoKXo1$JcM3rRn?sJO=q>;nZf%W9wloprokJ@iLKXNX8$5qC*k(= zTb0jC7$Z8_<2)>W;+4=#YqD1SLDfofMgy=fu#I|92}iYb!p>)<6tZz_dYYbT>GtM2 zOsE?{5b559pFAO>)BHaT+lAuz`1-anVFLuf^p+)EQ{9C`$3Vf|58Yp;K@3^KgLWU6h(Akyf6L%`2q+@4zUKT%x}RCyecpQO zn*;$}#TMWn5P|qp@;VC*1hNoLChw_nJ8WeCk?BeN?lE*V{VsP97aKqUsFD6p%jUZj zXe$-LgO`_>4`c2fNM#^5&qvOV;Qrfz-S#KaiNLe8X>-%JKD$3TGZYZo<3H}IU_wYa(J3l88o=V~PxJD1 ztTF83+p&%EOv%5HoC#c*iCcPWY&MQyvTvA{jp%xmu%sK$a^SbKoCSu<@Q|93`_;9e zt%ilE98V9Gb&lrg?lkGRyhW}+_6I}QW^UxtJjzYo`Qa*D$2>(S&e8#!_fn$dLkV9B0WF{ShM@2W3`xpv% z^&a8v0J98B)Ooaz4xiI3@r0fUh88(%)9WnP1{G^SAXRR^`9|hr&ssqP`hE!$FohyE zP3tJ>eUDJBzNj(;quovxnvwr)>9NV-me}R;`m35%Nr{4f{NfDqzENuI?R#g1m^2AN z3>Z(-T?wiZu#W_`x>-lkM-Hau*|29A-98y?{vpBHyHquP-RKHFKWlnErSh=#^xPP>a4J&lxFY^yF-qDl?b$FHrm;GtY(;QwVyREPQ#j~6^SV9zP>IYtA zI}*81;Z8S<7q6P;6_2_+h4p{GK!}j_%S#mQt4{ID*Azo;`~mi#zrdA+R(_7YCy`NQ z)BHQ4ix&>~;cfHLp5#@*!mJkV^IIc6zOaSF=j8;oyl$<$p+qxFl)$ba2ydAgYSfx_ zx=-t&-@jvgWYz=V3Xv$Yc~d^yF>6+9)YS)<&6MAcfO7*?mY>)eiXBV!5M}qS0F_0v zZBDyVQ~{QAKGz2<#k8vv3lQrI#7>xM^Wadx7%omB<>vsEz?A}fyN(Xs5t^n^_qc){ z?gBxN^8f}tFiA_J>htZ{YT?op<3z!pPQY+f7J$9o5?1ad$(v>p4SCbo4x(!fiqmp; zch?FI7=FO%bFxt7#P;k{<0l?Xgg6cvd;f)}7Kv#bIgNFfXU3Pdw4Yct!dd5IhsA}F zE;=~eR3IrWeWAu|R84;^5~C*OxK%-uyA{F*P~*?_cw|7l;q^Y-)t{gHOOC)CSd#t z_BI7yKj<`dMXjW<8Fs9D&Hll0{a1^h@P}DJ*7j*W8|xdWr151|mq56Kwwp zU3E6IC8-*Qa{90=!TZ~Ph?sw##Z-(=PRKX5oWpJQu*N~jkB&z;(igyeD-jwQ$5Eb> zcX2QOa*7csI+HUAJ238`KV&}ZyS9! z%3BiIX%=74T6k4TnyRWK89OdeJ$?D?qXTXLx+h^br13peR8(35PvKx2XgoOZ^N>hX zQnDyrts+>{5w4GHpMRAz}Zt$1vRqV zkjkgv6-){LwpM7P472qsrz>{;VGGN4Zxh#wU2MxXUmrfN=KRY-L}iM!r9sO45+)T|Nj(U`>FX<5 zchl?H(M=!XLBsg<-(ev(jO>}qIg6vOct14&Tm$^F@%hwF zo<1Y}f?ZdxV-*9lc668s$(TFGh_ zlShN3cm27oB||Be+;~vxXn{Ll>d%S_hpskz=v6bGGQH1Kp?Emq&FY0urexgZ#=gvI zl~-6p(CU^6l!L(?WF2oW8RrAUD%}s@cq}FEYNa82D}T;UpN<|*fHwEDV_!0bqrgZz z8nC7hr>TcFy%&+ADL|435{5{IJl#c?IA(|iImmx?f}Ys0v#E}XOFdK=k2LZ$;h;I%YlH>#AvDLIC4{nqzg&a-?zE|vBpU^v&nc?C=g&R{f)q>| z;x86I#by`Ky1-$+t^C4}k8o}s>w}zmSGahww6yfGh*%{En7&VWAld2t6s?0hdsGl} z#_hZ}7zq7jy1v$Sc@|CVG%d>+dgX4axOb*SC2muq@&B{JfT#Yf2*`kkQcS);_WhjQkRAF$I~pyC)C%(m+|T}2imf;B8vk+k;mV1Tcr6Sy_i9G^tyS*Jj) zvMlzQEmoD{1DAB#qrj`B9mxdK+mpp&{#OzogJ~Mh^}5GLxK$}>Y1Ni=Urx;SnY`EM zeF2)chZj)EZ3B&&tZmfvudj!WR`MlcVX0ak7YEYb!-=#XDDbHB#Sjn78u_dP@!hP7 zv$(z0el7Ykvv+p9Wv#1!2C~7SL-u;L#V_^s^~EExosY`OdS!<2fF05{iQ3A_jNWdb zINztckxh!Q_wb~HcDC{pG*sMjvTkrzAuala53*5?nCDM-plJ`Vff7nFv&@q>p8p#x zJbT5NWx&t&P2bTEduS8$O{jN7fJ`IIJC)wvGryForHUmFepL{D~N$ET#|V(WmnlhC1_TYh6_i z!?HMJxb%<&&<;m%uvXjb9re3s)}Tj5|5)M!YefSn;OuQMrs0m5IKBvfj)Oppf8Hym z6>O(`PT$b(w*L-xyUSu2%u|Pe+8Z2Qe)~@t10p-2b zqE%F)^yFYv3 zWgp(n>@!)6RkU0&4JIM|c2dDH5=Z`~`bnm`2APz7+LOQImuNB>+FX(ci`;vee%vnR zhu@3N*RL`_J~6cwhlD*0(TB*MC`KF*6~RYtzpX@-Xo9k8*vWcW;Y;_998;KrD#A_9 zD5p+~|7AyHih&qV&|$$t#Z$ZCucRP6YpHxQ`qyJq64(i0<)2Ccn2V4?&TqT@ zaG+rN`ub8&K=7wpip7I!Hj_wj>JAM7;41X(?IJjcf9TI_@D(wzAQM_&0Go`J%C?bk z$4ZJE=O!kL@ITvHJ|4EeH*xp#gY@xi=yJc4L=0+M?XVXdv=?Mgc{wuXg&@BNug9dP znvL_Xud?g6J8pjg!=`gqyg|N73K{^v*eO-j*~`5Q`{9SH{TUig8aYdHAi;7ZD6Hcg z&G!Iu_FW z)M{N2PXDkK{{J|F|DM{$IgG)<-&yFKyUu0MMmL<`gQ-H^sYw$Pc}<<(^I$HtECuzy ztx<{#A70gfwmpe1v1SsMcY$Va=p1IQhFtJZEHEx`ACa^;GChZ_-(gmBIhM-Kk8`gJ z+BA3H9+8RAYFrwiWInHf49W%!;+MUh;IEw7QqS9yOQxZ)2}_8MB8$j^y@8Br z)X!WA)ka`PBsV#PHT*=zLUS6%)7rWuUCEpijz@IU&kt^^nbp}~3%EBR`8~md#!+Va zIC5A(->rT;3DQ!MJ*?6-Tc_XLFYO2y_+YxJ>uy@@M}Q01$<}+A_*~eUsc)|a+~svg zNCO-rZI-l(EaePk3g01|Kb(r=Q%;AYRpkInajz__?B<%Ce}9%?i&IxLjEmpx4cb*M ze-84Y6PNtuE~Tkn;QJE zDlS2c`#&)fQ>c(jc6r1Zj@ttgo}S^rV2+$(ItH!0P(3#@jD?u0_Q=m*LM&MOghfc* zbAKmP%kUpjA@EwLlaN}JrczZ5q1&-L#axvT5vz=a<<Q9aZfCMMcAxY#ia%6&&&+||!{$z3;6 ziTNDO5w@sJfl!p~X>=3RTO!g9z60H^c1<4wQsWMoU=2sVocq|qu5|s(B$&}uQ!D35 zpj7`&8>_lOT4nUK>M?}GqzE_UyY;(%TcLq+QZloKVR^O{NN?-^KX#q}E)zFap?|!5 z>Th13)A~E1JjR9;L|o#+jkHu4gQS2ZY}=s`)AiH2!qrtvfq#liMcxZxW6WO3Ys}Cv z`y>bByp@zN1cWJ&8Q!L3q2KnDd(|rmkDV~c#F}!gOYQCVBPuPn;tD?tY*C34F?Fnb z+}h#2F>tzCew_c&Nbp+h6e!mj;$4fm1H*@vl_BKJzn2Av3FT34fgyn;poQFg<&m6N zDU|8lb;s(>p zKEyXaZa(I9M33J*zP`T;sC*4|wzZ+Q1EBp@+!ILNEPwokoAE z{_pem&xejI!ntoKNYQ703#uQ10k78N&lIyWU#Qb7MLMu}=)dj@CN?M_IMhg9Cgc-) zrx^9BwGmXZa*ivGOQgIdXbGJE$}!MK(6?U&qQ?>7nut`qgkbep-$!b<*-Fk#?(; zUlXp>t%KTYYqziZhkOK#qsH;G#QY@O0HlMCQ}Bua{brX#h9U>cV+s3|0gQKc?*u*K zYjsAR)ad~QDgTs^De#cdT{;$`(nhx($k5L9y#kH1y%7gB91pfgX~eptNC)%Ujc4)~ z{5_@!CXc@p%Zx=TZ(xIL4_+u4>QSeuU*&=Rj7Ueu(|A?CxK ze|nr%!BH|2@@z$0mycjtbO8fZm@eOyH#u{SZ%=Sbbs8Qlq`2;i6sqb0rr!s05jBKF zbl7SC`&Iu}DlLbCae?I1(>@^n#w;A=46h#ORPd*v*KtR{d+=RdRkDu#+o_`j257Z? zk_&zObTt68Ew<)%tmFAqroQv`y!p*eDjFCcjT)R8bi>MPpp zb{I0Gf}X;d7#`BPlPB7=eXG6mwC=CQ>g_fV!bqckc!ss)uD14~Oz^nqSdKi*GP$oKxJ-OpmNAZ&m^F z0uPPP8=yBmTwI|N1#+vXEVgy&{u!&*`OV#DKMzlTRPExj8;7Z^h!5w&3`};bg6_!) zr;`Bv$Gc;ix8u8xG zHCNx-V08w=?;DX5m$z?ku~XA54o&atP*8rN)@pV?W(bDAg~rH)A;GRQhRQ52SrKrx z)>5i~KZ-A%(-piZ)ATH;;!m7VvPxX{NWvMkGFg%GRQsvQu1ZS@$U_@u!vX8A@4kV^ zrgB8!sc=#+WNuB!gl(4`lTD&n9g*8S>H~46G$>+|lBk+qoHv~KnJD9mIg8hM)KHbe zD0Z8b`0N-?9o#%qd-6BDJ`lREKrWZ})?ytXeNdyNEt(Q^kIm~$*VaubGKVljM4Y;c ztCWe1iAW&}ew1`nWWllOh2i!9LHUZrkGD_jJk_LB68(Ft2qIK=fCHi@CWyi{V%2`* zP2;8#c%M4I@8v|NE!IP)3NYbyL@=;??d^|2*sffW8#6- zDhCT2CDr(Q+yR~k)92I%Esxfk^(*yfoHXz)C;4h!#2O%CYPby=EWO0>UEYBp2?`lMhUAM!+BV32>rDgr2 zLk9JMW|8(uVc|NQnnW@_KU)d>gS*NqevVk@y9AT+IZR8L;hH9P7A%!l4m$}(yLjOh z3V$nRnhC={>?W?tQ)~^a%3r*l@YJH(CcR>_j_ux0eQ8hFbv7VO%-JQ{R&yR{rR;1n z)%J)k!eQx53u|Uk6r?7>k_Oe6D1wAC0R9u`$uMV;fh}j z8CD%+lI|7C%nfL4XrbJCo@fOqxfG%DyN;L#eBXZc{+*n(TksziK#%T}HAm_2AI2V7 zFWtEPNjU(k+=S;EaG`%PSM=|W_noKm!O;;bkM4s@{aC=rZ$aQQP zEiGeS^1E(2O2T~Pn6kNJaCz>;A|g6UD>hW4aGqJmta4qgi4oiOB5|0v=f$E*;a>8{ z3(mKv28;y%J6rqnVJ?)tI1{(G;~nR%ZY9LkAR#Fiosya=LCajx+bR^*?!?i~t9yc* z&-TGO1$>}4z6yai4hgqDX;b{IO3JNaKErS^BnzYO?cFB1Sr!3W1(WmgJn*@)V_c5c zRKc+f2zWwxbYzTEh-ZZZow7IIHhX4=z3PC?85qD$@;%)#&|$zWTO zlvWG-pRm7^l`3UPX`_;}GFK>$&x{ivoWT;sCD;)oDJ&cq-#__Hca&5Bd|5CLiw)6a z`7qGP?~xU_1tF90Nqj}c|Bknurlg}(N_q4Jy$HOkFik32+fKsog}s!(VBhwFvuAaI zg$U!Jlqd^3y((sZE4=*bg6Es9S9_PxZjR3J+8NHZcgo`OVyK< zk-^q$IV{M?QwObSxa!a!&sU`Ej-*KY`L&DoZiL}pUhd;w7%`~Ezfg98XE@9higuj= zfl6v>)VywIvF|^)pWHi!F}@oGvWS#rr&MT=fmIMi&BMb}liqI_@tJFS0?+5rMWv;A ztoM+q3|Q2WDP1CPJ+nTziw*W!4EIKX{f~QF&~o`Lv_2-{-^Cd&7i-LdH-16+(KvQE z=i9IQ5zzZwC6894+R~6bW8mWwRxE&*o8@qro}q4J6r^wcUnXM`C8+(3zr-X5Lc^1z zy5shFpDwvpTW(W>4YMg{t1Uy|=#_k!JCnosd?l!o&zSR$j#YH-2xrS+(Iqdp7}Mi6 z0X)7syiy+NL+s1}XNj?T&3w?9KnrW1?X;pDUerRtp?A1OBS@3uTkM zIBHs^sTlHw$H)f^#H$RAFpD-wDJA2DU}Xr0l@Qxc)7y$ih|;g4jB#?zZu;amI&Ioo z(@8Fq)+Piai%&`?JiCe@Hm-{F@raH2^ zN3#Xvp3v5?e@_Gx1(Y8p5;a4xY(pe+Y;{xR{TO`LV-7MwD!uVQWUqN5k$?vTr5(1P z&5R|{p`ib*wv-JRr7Pj+7>-Q(2@mF4=rDOwv))cv#{5+y(3L5CAO5UEzCb>!oJH)= zC@F8B0loEfiK-_kMbtbS!hgEF4n>nI+M%b5yoNA0Qf&|FJDr9TLA;4ha&N(U7q$bDuVe2 zVEBq7V`7pj1TIz4Yotvu23KJk5&XBppTINJj5r$99T#qdQ`1Vm=vabZLYN%XbYBW& zGwAMC-78# z1TZwX&id;hsowL?lWwE0At79~mf7HRS@~}0P76s{$$9V3zFSyZyG0fLvUcsB@0QeJ zVBggNio!MpHctDN7&@H;RWG9LAP=tB?Sc}&W5E1vI>g&fhx}&{o#mH`hrMv z%xzN6Ro8C4T`Q{XC~2nr@wHcoK39w{>OmQ$d*2HcT#Aj$#+FF5poCV~8Qh)3xL&tl z3gU?L0u+|*pZ@0GG5??Qg+FkkR}Qk+0G z!iLNL)+3YXjXpc>_c6-P8s-D;XS&+kF(XKy0}@~Z1*CrI1JeA2n-yZ{H9OQvyzZZJ zdZuTy6Xr+%(`=2R8^oM?*+&0re>0=jg1kFQqFOdQl);^G{5GQNQ>;=DxbZyA3kvA9 z4G?pxUU3Jh@2pj%E41Q6}c`|I>}*p5)YxNDa?zXFlS||4#6v^MvrkaPA z2$S-Zg3R))&8{ih;7C!hn=SxdHzJ+e>i{7aXXxn`q-wqSWU%{Ec(>M9iG;faP@<7f zL#E$lcvuC!0>B^%04vRiddDL=!npF~SPN({@C9DzS3?4~vsn;&2dv=tVIjH>IO|Id zjjRUfLm&Y=v8%AK7Qp>%MRHjM2`Zq+sxX>17EEnz{ct>2rv5pZsZL_JMv^m%h!IWj zIY7(IKS1LEthuU6pC3*a4mUb(n_O(|RwE~`$RzHsbUR}Rc|UBTy(+PKT_?}$c`Mi3 zuEM40vQ%c0GCJF(G3Mv@P25n$_6`UOQA&C}VMm$ILTmwlGOVT-=1~gCy^AKG#Mrso z8Ny0pU#qn&@j36}t8+S=DqpEIvK{8!QTi3q}{b#!jXA zILULiOe|Q74_e5AGHTO$eer+A9_|??o_o_}o1(JQj%N&pit> zWx+vZ&}o#oyu6&fd=7*M#SM`7OUP|zGU&BpCm-w6(Fz##eq5|{Hqh7VEl5JuvK5P`}gjH(Nq z-}W3$Yyq_^dtD#E(Z9%>Oz+8Bb#WO#s-y|n@?Ak}l zbkm4er%=;4@QvpD{kJTmhq6l*JBG40Bf2st#6_X%`Y9=;MbO_HeK3yn5iX@FgP-w1 zZ^~YNWa211`x5E#hsRl6eYqS$Bu;hXdc8`Lipx$~b-hCKX<_3=O!teurT>Z>B5v{( z`KG7v-F3H?LH_^Db~e0303H|JUqO;OvFkY^&6G4$hH+-0iP+!{LP&SUb7*a{oKvQZ zAAABG1Q2utE(w<&vdmCYQ+Hw%nu$&qs(w-yI$$%JE5)sZ-=UEj%CrnC3EO^h*D-{%5t@U5yDW8Xv68U&6R;jNU) z{E+3}K8Vso6i+~&q>-QG^x^i?fMT?97uS$`OpH=KlxOOJDG zh$0*DBbgYRw|fTsr-V^zV>>9uhPi#wHRU22*92O}7hB#!R_%Dr;WA zhKgHRCExVd@L2G$_~GCu+7BiNX*u=F7IzR-S0<&h9SO62`%RY9^@l-cYzA5;*ozl& zSB!GU)trfKc|ImF4cC{a^*6nGo5gqYAdW{3N2*)F=bpQZ-^j{$7uHn)0eO!bUEEWd zYN3_jguFoO7dP6<-}ze$ zW+AkG4DrjzWRokM_8)6Z@VYs8=ie0hT@fYo!Me1@_-zwA)YhX#4o^MM5nZ>d|Ui8I&qSdWH`VTeT*$ zR*ZuhHmhyc|B*3~#5XSE)}O0J!xdfpTvM?Nk!GtZ%L%|>Vl6!mHxCQ!N4~e8z*T(` zhTqBEbhao)8dI}JV$w6=HIvVP!@L08F+?b!z0;UJZw%vc4nrB;uknaYdAY(s!RhYg z$NL=>XYs(y*Qq8O)!bn!I6FFMDL4n9>QCpQ;mg0xyAB=9#{wR#Q#ka>)eTl&To}Xm zE16kARJQJQGSrYuMcWLqHCVG!4I%@m@vAh-eitSC>?9mCgWO-@o_)}gC&0Wk*P>8s zuvD_zY%0NHecVHqxIt|SHtQHPv3V{D_D8@>kqML0-n0u z?N&howe9AbObiF>{sG`+K==sAPgi0vchPoT1TzHw<7*-s#3<5tX5pr^#`AKC%dM)o z+#3oYT*gkzAwi>F^r6F)?Lqq)&Cw@VC;S$v9hx8_d{#lXGFN+*$?#gXlr{!WRBSiC*SIKi0eVQSW)TxKGoC zp$gS-rIRgNFW_hyi{gWe*^X6b-}9~x5b*XcE$MFj2*ilc9b9#q0%LR8~I80=GEMR+aq*Ec~WGxR87$s~1+!x%1hISD%sD zm%IM^PpXvXAND-%4C4*d^#3q}|5k8pP-nIgSL`mfa#Oq{$0cSID~CrZCw_c^X~+|PbbXUb)z!T3sbcKvyuuxO%h?zqsna@OW{%(YcJ z4@0>m%XGOaD41_H92uymBpGJvRmMh4))cta!AKfPN-H1aeW~|pKCj6po7Dwop5%^1 zScHYPKnBzuo!2l12(v0SG8AdV)>Zq^sZd7iIuS->{_O(|)Q_4(=>8 zdenU}Yc<2H0a_H^VI-4H4qe$H2cgbD2mL}BaBao{zh4Q>>i#!LDLXigaPa(e5x9&n zh+5>dMYO4@F_0M13wd>bWyR!eR{xK2J{3V!+M=TD5-O3Zt#BiZ#F?7#ZW?Ha_F4f? zEXakGxf*%cy_^FYdl%uCX`D<<1fu>)m=9VhS{^_9Afp*X9uzC{%r5tpm6YBW77x?e z1VUccAY9N5Z1D|${~q1_vcW4FGAD-lD_!NTCD=j!)R#K$6+;{18RY25UvDx zcj6cR{6Rd)fDVI#sw$#9SEHmuu>7z4pN%*-v)x-ikjN$St}y6>8v@4#-(*mUdES+L z(a1Lr>cANX;OdXLl{1bXid}d~D+nsM6_N66nT~DJ;ZRwwvAsM}~bcd5B$F&+S zy;fd+zR?5(cs&5;dS=g=0WEHa`>IT{ZXqXI3^ z@(rNUl5J|a3Q2(I1tnu_RKtAA?xXe2N@>enGqOSC&@BA!WNN!>ZQh%gKdZw%hKW_*a=ytxn7!N&K-xN%?7?}h)qA1;Dm&o!_qZ{l~K9L61MBiQPR61G}zNtG!1o3WNxN2yz`OENlC9 zc7l}SsPp6dlbCHG04fP90#k2-VYrVdxStC;m!s(TWsHcMj)FIVhEt!0$9uVJqKC+k z6lUzihbU_FUSiS0HHydO;Nzf#%CTvDERFmQt#JA(jdnA|m^Wgc<1|9AYdf@EE$7IZ?-P1qlUDeo@xUb|TTO~dr`3=B z5-t)Yx4SdIDO-LvKpwT*lm}71xo0f$w3x*BemnehPa_GP^z^7-W7OH_hk{exLs^d_ z?9ToVhQ!yVV9FAAdySL|q;JNP7jl$#rK z887o2W&aLdplznsin+Nd`PnD_wGX*Da|&65zYq@77NPI5;r&$ltyZkt*<6IU(uf)< z3o{;l9jq&iImV_lbp||7*z^?@tB77N8zWmSDOXYok6Ek@U)w9s&sJ!4>+P0dpOF-O z^R$LYdEHc~!?-e<%hV#tOe&@ zw4#!*qk{rZvEhw`$6>-c_^7jdA4B=>o}B|*JbO{#zYGl(H3KM^I~2eoU?i*JFDzTg z^WMPI>VE~ysK9{Rshomlif6fQp?u@E_+gy`l^mpycx6nMJxW7{pc|BL=XrS{264&~ zy`E<}5*;IoH%9qLliNmz4*9z}416df^u9D@|AjAYEQtqzuz>EJ&(MAqDLnw;a8Rz& zZ}pj@R_Sd*@q1pG?L})+XzM`mTpFyY>bPBIMD3eU(JXRz4G&rWj(WG9z~Say`_1Vi zhe7xKOws3OgBWq{OwqmmNMY&*%VT}a3E&43_=aO3J9U?U&%J{ytTw_t5ExtNJ?j&@ zZiO!go2FoI!Ko0M*Qk|csFVRyMl;3THG-%s$38tAiPfn>dYmEj2{}28)C=KePTFyj z)|Hds+q6$P>s`wJA-NwEbq2n-%ko?q0D*O|2}EF|*uNVK=5d9}ZkCXhQE(?DH4BB>0uan{XVP z(qNCTI7~ulTb(pX`L6gyeiJ`0=rm-GkH*WXlZgZLwmUjBL8|jQ*;qIL52dA8d1r$#`ioMCIl=z_7Fd$xw@)Cw<-azfa{v|IA!20iaDq!MTcsznT;jp zX#B3T<}_mdN%E%&c%pin;Ru_n*=kSFuw z)B9c**p*6u+Kb9hSsdP9`;+wQtm>i@Y(~07!Zw?IgMI@!kZ^YC+1J6tNlFezwF?FI zk9&r{9Lfi{Uuoq;zabh^_=S{dM&KR%9H3yjRUrnUfs>$(c=QIAgaKx6_XC`!&?~Jq zjCflg=epvFx6zIDK})U*U?`CSwqlh0sy4F@%e=XVqt@I*Lht)_H-T| zQ~PT0-WjKMPWfbxO4i95tMweR##mNB#wD~AFou{D9BGM9r7ffbT5J<{G|M>djOKDb z(V3ago?8V|XlXpRE@*b(Uguz3ebED} zlcQaoTjkoj(|g6{ghDR)-y+KoedF5%`}uGhpFEfu-9}1%uy#G2bF1QQJyBm9agyC4#E|{(cVx z9kt60tih50F8NRjx+Y95=`XauV$4lOj}$d z?|#xq5lvvHI4+4n<<`s3=mmprQhz{lxy;WAgXCF6+_MeLFb11zB19)!tU;tT9j5mN zTdq@7E+Zx5aAWt&LtYDNR2Q2^$xRfSuWHA_el(EgMZZzv?}1b_)Lm26SxkO|f}TpC zqJeII$9RJWN%BY}u1jIF5C%Z_`^uU>m%F)0zzdzS^h<=`00{H3el8yLTdQU4imsRg zzxCjlM;GBq<1{i@n&N9rzx zb~Sf7Ek_!Zl8Ts=pT<=8cBcAXq%P_b(p;O{cP4&?Gen`^hSYnGh@MNo=~V}(+4!+U z7%YiV9IjC)+hsb{n2_~fcLhID;h*(6Ki()p-L%~a#({at8ju6oC>iL2&u$M99nVN< z9UID#{Ekjo48tQAKfgochoA8rKvms0Dh@`qLP}uB4fIK;K$fflUhPxt1)uh-y~pKx zIqcyh4s~WaaJ`&2wUGN?@rq^)e>lM=A3p64yj}3|P4O{}`&?;rt)WCTbKwivgkWdV z#dEItNZ$rNe`T$9x*@=4JEKl>KDHS;Sd-m$0>iCKm@KX?C)`EU`%T|Af@6fvQ4?sg zJTP%4g8|OCTiJJEOx#WAbu(T zb_&|%U4KBu!LsRuigw zc7siX?|wV2!l3-KokK;P-S9tOwy&Kx-yxnF3tn{YGKa9n;3z|Ukn;xW|2X4dKDu+RuuhC3t*0`tcQ)Yx%#Bb(9suI3gQCmGa+ki1@- zYy3Pr_JcRD@+61VB5=>hj@ayqHP8g7MP+TTX zI0o;3^!9r3GK%1q0W0T*Op)17H>@&k4cpyPkqePpb!6hFQI3b-kId%NU&a3}cm*ah zhc2tc??yJH!%A1kB%1pTn+eo2!f}~)!qVx^)Q3?4?8%1QhL0wyg0(Q`$o)|mjy$88 zJP*}=u;Ohe^zv-S$CsWivMF0!d})$ea5fOd*J5-F?(?Qbh`+uiPP8)uI_Xi=bBccE zwX|JFIlJt5YXey(plx$2HMF#j-=jZcZ}2*H!%(q(zwnvQSYbQUL21s&7SYccF_9MjJj3i)x@T z_d*q{a*g+ibaj*OY~F=m{7Q)5HrdS0udEb+N?AX~Kw`(=wuv^mIg7ri(C~Y`(*Nm? zv)E>h#*o%v0I3!Z?EIYJ3omrE<(>9pmC#sIzOk}65p69Cp4B_lO9l+Z;OM9Ia=u7y z^zIQ;561(O;%$?kH_<8rfp02L{=|fiQQL%!-%B>U+SJEMrYiL9!vo!usif71=$SjH zk2eBCZ1Y#P@i@@}0?uZ6m7RnqzK9KMuWra!MwcfNe-ml*y0L1UjZP*Lffufr1=QUg zENlmCVkFzg{AMX=n~!^f>^ zD=EjDzBG?k`@lNV1?Ash*46I|h(w;_kByFYwJ4HaAKzSd2+4pJorPBCom!b`X;IQK za#*VO$9^DMpNL$(K9L?j4R3V4TnNOI6LQ)lsO$McJI>-BzL@{MVAAE4c2a8fxt=t) zsw%%j@R%ZxReS5@B#a<%dc09`KfQ_tMa{3z^ubdCT{nr&-mgo?zTX~Z@dUlZTsKXK zqtC}H$LDdLjRe6;?@Vm=JeCp%m_7#vi?gr!*vSdD(wGc(L5Brij7Wumw-d#|^XAaI zD%OyI#X_7D%JncbQYfW%n#@T)Fjsqix9x6i-u&xbj4_}M+vj%C{PA@o%h5l^)*1nb z2zi@+AbXBGVsvgt6eSS1`L59*RDC5(-B<9dax!wDHB8`ime!lha{a}Vtp*;>E%E}J z!FT{a^uPb;-1UaLCzow~ARPHuFG|4;{5BYpnNkKa6ayMiDYCea5jBDHZ&{k2;HezB z9YGagA`=i1>tQ553a=;D^21;uBmYd&w{S5P4NJ||A~Y-Zj)w~=m%ugfbpC40iW zvmGN4|4xIVFTjQv!pUzqPZDrc&Cq@#9Dv+1nQ`8l$Km5G`{pb8s#iOJp^=dZ?=JVcflp+lo*8I!;t*U3*C?x=Hnll zY0xvb%-;0N$)F;|E|}8Nv*U?LT^M5>sd6;1Py`K!918{;87j4eVOD7iC4)T-GN9RO z%V{B#>uE_VEjLG}xQnrl%cP1yYloH=XqNFN4+E%=WCAXSV|c%gS@1iE)b7JjyL}lX zu3lf@End>n_=N{kM)u0IO@_Amj;LpuB`kbM%BT5#z>2ipVV2*cWm*s{dPVEycc1%L zcqJXJTz$yq%B)E9+xDk35t;P_FJD55d>)1`3TTkAo4Qx}B#HMyJ&2~%ev;f>M0p4w zSH9USqpOk`Q==w4V~O4CB}#C3{3Hl@2HW4fjm-1I&mjAj&#CUJZN0Yv0p{r@G~2pt zU#|LOYAIdibr+nywO|=_oyYmU@a_)E(_{L5_J^*e3{LwMV1~f#xFpcAd~~0l&5-yYn*H5xqZ?rLtB>*_EKF$HXtz?LKr)+Dt!9` zE`8ju-Gwhu+Klar)KGS%8ihzrU0$m}#KW(9ob6=m4-quG<-8r=9j(h|U?Wo4cMxyH zxs#(rxKOp2oiFetP5QFtQ-3iZSql;7RsrbW8^h!BO}sQpqteeEC(sil-qE~QKRP_x z@ffel&`?QC$swu5I?b8K8NQt5tzK*E`6vUATV6Ndp{1#cs7s8~8^0A!2#Oenw9}dR zazZyUNv*Lpzx`8BWg{-sL!3--+)~^z9V?;)jcfx+GB%$^~-4x79Z^aTui{I%Dv?UuFb-U6u)NWjm-4%jMFgh{p zqaBV4iX;#S`!Hx8v@T8EzIws4&QAx(7{?i~6^QVG!=LL7|16gn(PbpGrd^+vysJYg zUgAG@h&#vP5*3Z+Ar2ECdzM}*WnBhdjkLgr6rlHL>D2dd|Mn#d3pe=AtUc!3({%mx z(f<1DLc>2Zl>e@d|1YQApVEere8Y^oB6g2wF^E0bu&~An?aV(0jsa@L3dlLr?aZdtKjC^JW6{}sB z=g=2r=X1~mBR#SKmMLV(G*|O;Y9)1d@l?|2Am?wf0I;&30ECDG#sewAWSUqQ887Ak zN7!41Mb>Rg+PFJ~ySux)ySqbCxVt+P?uEO%yAS~kn6gpWw{Ue`0#oX}j53uE1#S*cB}oWN37V=+1# zUB`vYSU0EnTzKRkegLq|B%~k;LAQ+-_*-$nRchU)OT2D)AN-`RqO=+#!a!tQ1~oB--IRR9f=`iK<2+8t{y&~4EQ|x(!6*cMGZ+=J_e4N33^?lTsejFw%(I(!Em*vsY zFym?qKFkf?&^qE{rUfWhN$rcay~?`YbPbisjb&Ot%&vuv$<9MhipG27qp&1mN? zrobDz7Qn})_78JMu*p(8Zx)ThsPdoZK!}^8zG5H*qlHL7^!m&>;)}x!6}1{hJ;Ttm zI-0YMB2tKu$V3^Y%gx?$L)K3E3{FbT8VVc&q4@{}5}1R$J`r&p4dhuB=nurfDPpXd zwe?xrH%)!>;&+7NEXXWzbB}H!ziAjoC7>8Z zV22e6cQ^V9oKxIR#>A*8?EkVeC54rrNX5F}bKj)sRjSWBLY=tp2|i?eAd#8js!z^ zsI4qN^xF^_OAI{t11d8s9`n2{ z%$mp26A2z);qa%TQCW}{8wUszZof`^juU};v=Yv7RWov}{ML>tbiVIcMo-v;w9S@Y zp1hzEuMxQ&y4z{@UwZEUO27Pv>s(T7cOq%$*H|$IGF7)soHc@!V)_2BGy@f4)w-c? zl;bCQ_8k&3HfWK+O!oZvMoA>aIV*Cp9<6~@G*7k)x~{w{4W$*2F%SNf?w3_j?v}@an^UQ%i`bOV& zMwzqh{&kY$aY(*7(irRN^)`gAlu{}^qiGr=!E3W@o5BaOA3#XC zU6tDY7YXaUZQHvlm#&U_<>Ub7a3Rxca7012JAH6HUL5vu=+Z;_?}b-H%^@J<>N?=T z;j5IqKbg4yCFYMCGr)_;Ki>0+&naFSlbW+X!a^X(nW9%~<=(HMbqfYYf7lP9Z|Aw* zfmr9P??QiSxY&%gH4|EZ^-U){s~_X}9I>qjVYFFqsbh zM^sWjTJ)*X5>83G#m1c3L>`yj`^#UGxSk^%HujQ;rsGaZ4a3xSBN$TvEsJFW6!m4cW<4DkBSPO zl0J-A62oI7X)(mf40NaqZqu0@>uJ0b%a%iDzJu=)T~RynB9wlBx-Z?{ zmuUy<82!%ZFNW#?tGyjzeQ90D=N;x%Z85~4=%Bzjph=tGK;Pyh>%{zP=sF+H#{YJo z=zwp>RKa`uanP=2F}7_=A?i810`VI`~Q8;g#TpDEl>L}RSE<5$l6V@xfOMMS7B0S4m^_!%aa&G!M0`fH z%}4l(SFe}ziEM-874TP<#Fgl$jIgA7a+Z#KIGVQK@&a&y^pjb#bH~<`%~XeV!(2WC zdmG;8t|?qS*%Wc|_ko~NuLs!$HTVD5<>a5M3Ku^Zut#Y*%0v;#Y(DAjxhy#gXxE1Y zOS5nCiZ!Q>nhS@r^eS1%17_F8wG}4}JByRYh~ceSyo@5WlbfZfRE&_ZvRzXNVWTg+ zPvyXHTjeXw><|sw=2a^RSp?)noYVW&=&P$;k?`z><63c+l@SpmqocTU$eC!mlr$aw z)tLfpdkeC;ZE18}Q>77>zlo_e*urPMQLge#LZ+S5QK7*Ja!E{N>8}#+<#(3f+MExr zLb)=Ay=^d~+BNOQi~O;RpNTCMv-yjAOcY;9JN~Sg{cv$GkA5o_%?M~Dc$HFdZ+X8< z?~{!ATf*vbrSEl|;qd$K3%-2!mv&9e$@Ck<^0trpYs{H5zyL6ot#>?eQP)Qjjl~o! zzfF~NPRuvA`~zj9p&lkCE@)EASYG~gon1&siD6mBm+kLXm(;jEBYkA>@LIRmef^Db zpKcVJ{VT8|@6cjMj*3Pxy>VTe!3+EY)IDbMRS2~%XF1oEnrMaPZ zq~|+DT_MoB3QoD|pu)!<10L6!jPpapfDZZ(R?q8s6|P(-u30Bzy{KS%>a!<;envfC zKRN?>9eDZiO<_THH&@EVwbH5RhP!SGj%La}6E)8V&4|WPoQ8S3ZMRvdo+(g9_{ zfTuTvS?>fWwsq{a1+!T6_|m%P_zAoaQQX#x$y&N z&UCl5gJWc+D$g8=ID>!HG5lXo@_&68RD~8aspQWUA!7L(kDQ?w+H%09T6K?37T?%@{k~GR$M(wkIvbkw;PPhIbJiR&{-F z4A$0v^$Ey#9{hOw9{aY{B8LT>lt0DF0Y5S5jB~bR7pee^=JkCx@Nu&}$={yU%~$ z$LdSK67dc=;oC|42M6rlo>!LTVJWfmEe~%m^2&+MDL&w#h=^v!_w(77hR>M{#Mq7< zVg?=bNot)6@@PviQU@hIHY$f5Qy8*g*c|bJR z8=(R5!5&PBNZa_^l6m$3DH+2zLnE{4lkU+^+?@c0%~7Pckb8x=ephiii_o|V7aP+@ zerrm`cVy;vZeXyhspBTm)`cVOh9H2Vt@Ya^0^ z*0y?y!PbU012=CQGfyh3273DbhG&n*A4^H;v6J}b;l3v44=0x<=EO4EOhI(3*?+91 z|8tW2=cko#VCiA+%N0|`U|I$&$-6`5lr`lWC1v9X+6Y2-OHwJq-(${Zate>WUh0Iz z^-s2lb-oNvz9*_QHqwz$kZjKQGZs)F1Qt#Km z(32I=dh1n&fd4Dn`3=>BL)G-aEQPtQq7npisLjx{u&5Zg0J<~!x)2(>?|aLk4}80K z|EntUKH87ygAsYj?e%(AXM=DBw7Dy9^^T4P9V$;g>uQ%0qybIk*YI zh))|D5~m4u;|E#%)!@n#P*j?bWt0RmjU9iygO|12r;>+e z`gA>=zQq@B+%N~q<5nzvzQ-eWzE8r1d1nR=hVPVf1_|*+%CgP=wjN%!Uiu-8V2A>4 z#R$3SQluYHpfDdSzbJBG%!RmB-Q9_QZ3(YpG~wy+#X(r1=OMBg~PVsKT@$=oSx zl0m3dixZqyOg}!*#w%(5rSKTy`@gHW|9LkB?lnG09d*X8DR0h-DZRp^&o=7ne4#Z5 z$ODvu#(d9?(hr+v1=Gc~p>~{3{yNt9MZceG^(~GYqvfZQI+3Pm&Nj=F1>puoonSAv z0KYLWYqJ5AfK9jb_ZwiBjrMeC6AoTINY0T=u1Hb$Q4c z`h)5htw?{P?@*T-nVraMlfImEGj75W3f6569MEW?CkFDj1N zi)OgG$`l;p8(_xWn9rjHD>8Wi#(r!S1usbH#x1pWzyfc4RPx0?c<;Qg_Y+Z% zgKi^^ew(#t(O16U0@&;&TL3DcRR#?BPz+~fl6qO{=N#5u#IYww8$t4 zg*2WTr8X-4Ws-rGqmCrotzCKXlY*uJ;X|=vQ5-`Se?Z?=PA0{W=fh&)p+HpwhpelW zAgKgib8>m9tK@+j6N7_1_(nmP0Ok#3VD)UiFjMQHm7Zl^qMHI7=<8}ojn*`AbwBsGm`UU>?#leeXvFFpijD7Xs)BoQJVS)?=HDj*n#dlX?MV1bRl9T7R%>F+s=Ma(s(PVnbMuxSv(p#FLuFt zm`wF|N{$S@&nRSMWK^_HsYF&;nT{P*W^__l7P+IHb@|wcw*0g-H7hjq+3ELAb@?ec zGz@al!F3~CXxs7M$P3ZYgfoSgoX045^1{1at!BEj$>XA;G(7eR);$6x+&N~_<(!;Y zZcHvU&>+DO%v!FB56Mw3mfDf3#9=5h6akm6N|S!)*&vhWp2jn)2SX%CZX^5c1p3|R z-_M6Taa=Odw{6vET}=z)O4>DtA;Ca`0E`qA8dy-w0W^^S?S#vr`7Q}d!U;ur`Cy14 z`iLbD37)z^JAUTq-w_Q1e6FYE%~GiAn!)j%a~e51_d0|i-#g;aYoK_tl%^g{MD)bW zhcIlo&LF=Cjy{}b3oFq3`^{rv-DKZAA8-c*6dT-46v5yX~4$g?e!s1p{jwDrU#v@C5ho)F%N zDZNqYnSMjG^cX4TQiR;8$$AhN64FBH^p%1D2%U)M<>ubFm>4rk>Cu5=UeEdRpAanA zByVk4V*~N66KNdK#g#B-@%cidMzZ}2vG1}N;my{Ydw_^MHmbIEIM!zZP(nr8rz~H~ zO%JBA`AXpxOV4P#W)!<33;vqE3L5kyF3Nz`+o_jJ6>l>{2ALmIsN0I^_pSuGHdHR* zHnVpHF1BQ^N~ZlRsY3xAm<6}kUmGc+jWbDl8^YuowL5odw}N+^qF9U9SI}WE{wZ(1 zhLKv@g>l^j1A7%M_afVpFMDC@?Z|71*d9N&W&xzgNfYLLU@Wx^pVa+C7K6#>1Sxxh zI})U~S9=@9^TffbnV1xc{iK)0=@^W8ZkQFs&^ANo#k}Gr0ScX+9G2Su@pmeE=OqY>veYHg8pO>Ab>!W*M8@S8 zUTA= z53klv?NjQcCWPe1g!lmj0Mz5}_@*gpf?K5v-q~;DFFYjpczAUX&7FRakI);`37pxB zkHu^(#yaOiulhMZNGQ`~Oy68Koh9eH-j+K_l8ad{ED)SH!%o&}b+!FgOoZTSmpK^e zqsj6*4J8D31cyU`CuUjiA7T(|WllI}t1S$8wC#(L=fad(8jJHm?6Jub+`ZI>&%Q&C~;lOy z4=AEi@~6Aj2hr^^9-bIggA}xiQJ?FB{x_+o@%?_<`O+A5?2cPsETGyi^J2v}Z_P8Hykw>M*7jcD zspg9An%AXuCNb=N=H-yyIzwd?IpDRqrYgRG;um*Xy;7Y-S9#vGrDrUUhUMbUz93r* zOGEe5!FqzQgFq0xcbwfmRXO_Gr?Z>}w}FA)KwT662GKwymPW7PoL_H{{hxOyu zfEb^x?b@7cROd+Tds8vP-6MO~NCTUopdhvo&(pxTFO0+TpdfoU!%wi83iXdF2GO+R z*@RY%za`zr6+Dtt7bDxpJbFBm{^6=J^0FzU^xA4YexoPDCE5qj;TryU&Z!*Wi=;e{a98&CbcV-tWJIaJZVqlqFLK-UnFPRXTQV*$SZ3)q ztEPFkxf8W00K-cx`a)Mt`1i^Z6DwwhFmkkc-0V6JC~14X?t|yHa<`5>{7AKSB4;is zD`~t;9)#QA{4&orhk&Dz?Q^#O7G?TxPYv)e+jS;E!9Y!Zicha%%@H0P!ubxe}@uncHdRR`4xub z50;vopCa9(f8<|9<@Hl>Klfy#o)3(D*qAUjqiMiVTWa!a-J*xm7^ zwHyL4n)$nWgK9~ngyj5|%&_Ixfpgesc2yX=YWI1YiLbPpU$EOZ`+$q=0>NqCf z7SlC2r_v<#rQ5b?Ir8Twr~1%IuSpxyK~>F*x5r@0eAjW@5+p0(`3@n9twlT|u*^5HPLfXlKh@680S) zDe}2nMreHMa(?R$WalSZx+!F1!7Md+h-q^V*NA7|4$*joE z)Ra81bt}%BlgIrMn@w17->Jx8NQUk^5Ba%5iw0(`3(CVmVRBSvcHycr62qt0&)Xid zC7TIgv$4fU3{K7v_`W*mvMh4Llb$62 z_}H=s;Y2~LK6Qk5;ojCTRqn~aATR_hkClcWp+z_W(}QQ62S{g)K*Fn>UE7z4F3$B1 zJ1f!_p~ga=lY@UG{dN^!H*NRPV=O?x=a$5G-46aJgmldp)oAzTZdc_%g!Q6Act3xa z4an4PC2zB0_>H;|XAoYI5qdoV6gn*i!x5?LzA&)1t8Nyb@=AmW@0$p0%llTk zcf1LCE5(lyYpdihyRHf7M(iD<|h{pb{n6R=Gfl5 z3f`td(DL?IKYhVErB)*-yl z)I59|Y_tyRu0#a<9ZkCrZYLt)Uv#FVK85F4+sA!WHvMhjm>gBTayBU-3p0-JxBZ>h z@2!WfRY9;O4tyjA&Wm+S`dG z#NCsBq+TS%YpIUgi_wT9zRn%zK;RuHGUs;AJo|fDPs#9z#Y|BY3vc+b@$U(#b%!SL&ODJjJTT9MFm3tvML4Iz-t zMv=#k18($$2NFu;cl^or1$0aoIIYRQRG3ahl90nv`pKgz>`2_l$^f9O`Z+Tj6Nyam z(!ieh-nvBn?{Cfcu2oCJXo*QMU>)dV)~!NdcR7@mNF4LLk$Bfa7EMrXk;K|Ru)akO zxs9Zqv?rvPh{D(n{%jr5WxbDwL$oo1hyD>mFtzx_UG(YbpDBFQxb zaH!(R&qYS(M~n5@c>4S8{S0 zPAK3$c>zjF3`-~z82YZ>PIn6m&7JPguLkx)GWfK3tqb!U0|%Hep%%>s|4N3g{|t?LIy2qyLmLJ=?M= z&IMK9cey|%H(mwA^p69ZBbLrv;YjEtV>@9nrv*ZD)mM>|6U<2q#syPP`U!%oU4|NL z)Xe^F7X2;LJuM`p5Cz}Yg%p9=noX9rG@KxFCbxGZ^0I2+vpZ+kX?85Q+-cL2u}>>` zWV|meEe-A_A~6bf-D)uFLQ9z$z`s+bf;}1w^h6?RV@IC2??nN0W?EBdSFmhg=5j5P zdWdAn5XelZAXzZ`^WAsUkR_84+Ch26_*#Qb-(f3>nSFc0*$y#O&|Zyr-3^8bETt{C z#g}Zv|73CC-$z^_osuiwAGyE6bqG&7Ugcz;o8K_WC#!f}T~VuKb2FRotfxq`Cu#w4 z@nE{)7qwKcTfxo^i+ZiH%-HRv2{M8{`Gk>ZvK=?2sVf)u-&SiKG@D8ye=H(LsvY+N zkSYtp{UwQ-X{8H-TSG7sb55sSV9k46UgEAY^UEz~SRZrl?u&}Loo{i$s;I3_dc0V! zm~;uZ{__@MhalRN%tIL(|kuL==w|0MUT@#lL<9tvL5o! z52XBZk0T%j~`(SA62NUhO5g}t<3Sy$Sj z%;vkqYe8Y`>IsiFGWrK>X}Qaa_PP8LJv@JRgE6U=qBUQp%IpSu{#-Dee$$+C|1Y4$ zf8JUDt?s}}?!qPSWJAGI?ushhj`C_?@>cNyoeB?&UPKko-@){LCAjc#ubn(Pb99b- z4~d0kZAsEh9S9k+5q3rC<#arhiEWfRi)C6Py!CC?`eXrW)R^dJj%y8PXLo_pi{w7z^h`azk3#Cu#PHHaX6@Iacoc+T* zg+9r-rh-ofmp!;X%&G}jKa1)&1;@$!eHG^nx%Z(vmLR>u5)|VV&~aEQ;=iS*P4Wfk zGipdwM{CaeOGAAe(uMr!ijtE4D{**RaD%I#K)cl8fPCV@n(1nh6V#oO!S#UDvs<`tWm zt3PIvll28+CM{bcKu&(mUz#x{b$sq_7Xha?Zc`OQjbg479Jw^s&R)duwQcr}|B47#+cuGbmj#L-y1Xh_txp9}8ou|}P? z8Q;>s$w3>t0{u1rXtNg--+$!JlQm2i_jIoAr4LIrEjPE!pn-wal;^kk2(z z|9@(Zo^Ft_q+;@zkqEy@o&t_{e}mthmF4}W{Y+UjEr|Akda+%iBMiBrk0BJ0o!=AK zohuM)G<|XAkN0`t6)EKkS1FQ&y)W7I@dVi^@VY;?`T_RD?kl-b))vC|{dR%W4%rf*)*e1kgah`n~0yywI-7nHW4TRk6e)~502cltN(Xq{4p;IYJ@AUeWkU6gR_#o$ASUA5w!{Wrf1#k@z9UdO;CzDytr2>+6 zY&sifr!HxLOK)~Zyz0M%te*AnSAagLUl88&ksyYHOFxCkin8zr3$rljG^vqNBkTO# zsQimw8vb8K2FDtp8e!(&hLDtJZry8PpI!6|;kztywKtBbtV8?X@zT%HHGemTG$_s*Cp`Yn>NYtO^-)J6jq`dBIVY3MUNaFzcm3sq&# z(kH;(DnJA=CzaSv_OkT!Yo{E>EE;V-@{@I9HC&8 zV%A|>bQk`4a?7zYMa^}6o}{6!L0Pc=C6JqeRzlt~F)^`s-l01oY^|lCA({t8L2OAn z!aiQpLkuD#{|IKn12c4ml(0J`gnOv(rBiXa(WT{-!)cd^06s2}bhp|-HeX>TMX^Im zH$m}rC_^zX4Fb$P=G2?lhCe=$Y$j9Vz>9VwrS(f85kbkUC;*G^AW#E#K{m+;JF||g zUS#3-*b{<#3Px!XM)^E06PQ#=!G7`4mq@L`o(9RRgk#4da8hNxiih!+bY;Lu~hO7@gce(%G`LVm}7kc0q&gn;z@ zWcc8lxq^^^3j*Hebm*%tA_$XKe5j1^Uw?ZPBC8rwCUTd;IaAX9n@Iz@o2F237+~)MCH8*!n6{|GMI1KKe zI!kBJ6TwdQ^*_Hb8ZC^d8AApmT0R>m4kPk;K=mVB9l>EM9o%v&n7B+|K*pY31FT#6^(_Ru)J-U_#EN(kzQBfr`A2$M_(eP|jb4Hg z$UD;c$3EM@^LBR|xvdq2;tD`YN6R8?-v?_yP;KQPa&YFvV!gRSRyc2nO+@YnNGmf7 z8e;dkU^*Yc_Og9CAlj(9Vc ziH%+X^CH&CKThtQ5699w=Zb7r7+Ib6A%N8gMXfCcUF`xdG+YljwQ4NF938~lJ^ z&Ls(aCBa*6*GmY4y?sJ>jFbduO|MhF=blRtu)Nvf3N=Wen)Y!imAw+o4P-7#T;ps^ zTu(mze?T4M;pD>eo%=$2|DybylV5m^*zB|cRrb?)WYC%_GIn9pn0n( zW$DxD^Kt2G&iv*2uX{Qp8kp}I!edc_m*QJ`?@o_&4Lb|aRQ$h>8QJJy+f$d>a0cB| zCgR#vqO%DRO@5Z`o0ZarHx{$9-fS)x$;RIflGH+r@2xs!wMSn#`&WEkpDxj4tRqCQ zti{xHEYla*`v?q7AZDJk4NSJGy~TDb#XxHPiq6SP{IU^nG8hEBJpwT-c}#uzq8*+N zv*i#TLsm_+Dz+$QZBAy%9?G;~kM4NdW@XvV&Z)CcNRfTHw#JmfwJu`JV%3Oy`5xs{ z_RL<#djCcoE#A^P{%~^qz(*vV?HGSb2y?xm%CzfFT7e%5>hcu!`yEkqQsE_yB|c})?!V7 zxGNlv&JJUjmScn>e(6HPY$H#RNvaKNaWFK@)%}&E&Hy^zZoMQ+A?Ncjma<0dD;3ub zyF99wlHChA3RF>XO`{x^u$Rbb*FN!^%bJV7@g~ky@R8LJ^P*uOjE9 z3j{`Vh>gS&kiD5m7=YSr+G?Y*5gpy-4v!93(C-h1LH@0;H~k&VWbD?1^*0)XQf#p^ z3m)$I9oWP+fjveS=JtqXM6X=skfspm_MFY*68H!@oW|116>@6893Xh*)Vn;)>GEd) zcvDQFkAw7*n+(t`0h+APz2hLCy39XM@-8~m6HdvyWtNktPS|AHUNt;t(ijX1F-LrB z|KQV0QV%z^h(Z;9w79i+#%UJRCchd)hHX5lCd@ZKm2&XZ997U=Y#?!M>!Uc$Zh4IB zIrP*l?~*Ub6yC3$M_faU|HvhS(r*?{%A37KrO(_IMP&@kABE60Y4X!&7rA>GL>3BM zdet<*?|(jS)?GP4+Bq6erZh>E&J?6#JoW;|Y(5OW86CiVKwPvMx-mI#FcxGsH+YZ~ zmb(SjHWm>L0Nzx*nGTf0y(_BxH_4LbU_GI{@?Q3Ow1cln#Zc7;miRaJ=|{R~6BU@i zyI1sG2d>RAUQwPb-xG$8KTbjX+LcXc98XBYxyJ%_Ki_t7Oetm=}g%kX9Nyi&Tbnx1OIf4wJWLi@v>473_|1k}1NGyjkG12))6d_M+d->lIs zJY!T8pEEj^fRpNtuJlS|<_cI!Y0*Exj1U-RMi24ShpP>R*F)Fz=R@iWsN2}nLD|DZ z|3wnfH(9CBSCYXz2hl+AU>J%{1Fwn_3eS*~AQ*X&piB_>X>V?U_|UQtsG2TOG_`|b zC3~uIf)o#(kg`sTmeI+Kr_Gw#VWl4{H*)AyQ%dRicY=k9=W_Q|sGzK%$b+ z+qY1i*v{A)VAP9y49G_T1%8&PYL z95NBQLf~O?dKxsUL(D=VaEQz+J9nFK=-_*T&qk^*zgwjU>;`v2v#ptDp$5;mFj{Yw zRvnT#m++S_ejNm%Ujwl*&CeUjy{j|C0|W7pNBmi?atV8D>qbV={HyBGVWc`Ov{Z7I zU(?DsNhe_Opv_Q}XG#}NXj?-TY_8W^eDJ?K)B%g+^fHR`v0Q+&v~G0zp|e_Fg8lDo zEV-Oprj~%SqN}U)KmCo2#L4y>G7;Qs)hf%@kmaex9LAlED){S= zMyCUB?Z04T{4TEOJ6#@33Ae78av6XFC z8bu{IeR`H}=0evvQTCnemSZ5TA*_q0M6+11u8fjnfsfuuxjmcN`U!xHbA})Yx9{IQ z4(s~anh^9tr+*8Sy}A0Yx(kW{r(|{8j{1v-eh(?s`zPjrn~)gYT#m1ZNWr=6MSyp{cKeS4#@>QY+l_%Rqp_8~Pmawx z#kpAk%VJbT!>r5b)5^b4P#4gkPu=NN=?Cf%qhfMcsG!Kyzk7Z!9Qmfz*_7YP-`Z3v zr3h%PT-F@(T|Igu|LyXh7ECK`|M#;k%m!hvf0re^8vVU#^f%JKRweB!DCMcYAlh>X z=cQO#`T8$BC4^-U$_$fJRTQEe;^SuMNQvrR&!VMcXm}Gqj0wC5b$Wpl4^3G&Ef`}kdVc-bpDXP@wR>F=*9;_D?@45u+v zk-#cL!pa2xC`9Pd`ePZM@%Hrr=<0j<&h8o-`eFZk?9&I>y56>_>v8|6YiSMA3DN`6 zhoI;4vg{9p*#t!~wTpv46X4Cunrp40&$F=T6w@5EJrahtUqzmz;9j{YF*L>(_T;xO zR(m{y9IOCuoIFm;G47DnF&>hCl=%{D(O!Cej74Qb1i z{>W?*SMZ!=L$gj}R9*No^4ey&+%PB22olpCeT@J8emZJbi1IFh|NO#cT8>Zz90WLp z3>J6KZ9jku4p{aUAY<*cLmCymhI`<{_H)g0O@2I4cMMPx67vI~e>xlrNNP?Xf4%NG z3bTR);=L@FKk!oTyw+=hbQ>5(pDbe84}vPBril6E2nm{x8SA}jYG_z=TQ`^7I)gqz zMLrT*3f>0+%+Zd5$oH?csct>OJmIBd@w}>AX!?wjok4*p21r~ZN@Va0ycN1WR=R-v zvBdK%ex4@03yWMAq7HH;!Il=cT5$8=z?eOXd{qmQeB(e!{u9mQww(p8#<0slp{qpu z40AqR?|2Svq#rS8ppObXAk~TB-$bbcAf^(_p!6KnPN)_oe>iAMsa-<|+xEXw%kc&n zYVNfo?sPfC@02K3TY;Yu7{B;IMS8Q6Wr&BhvA-)r^h7ma&T(N zQ$1qhQ`^1D8W)c9c?9HqWoCWOV!RKtKY#yZO-o1HI@o+;1)wXq3ah~_1`s+U9paDi z-1v-v@-A|F=J@T+`xHA#iroGh?H%n@FAs=Mbal3G-SsMblegJDg#9Aq4}zWIgR!Jf zX7T=Pivo8{@IvROrxrMQw>6#1FpP?*@VkR^xr@fo56~entmgkpxTA@|IT^6O(#O+hHq6No)h`F%WF(YMNO%<~O4ED3W+G)Jg9BeuGq{Da=nV?8JeD4Fv+l z1cC&Z$i%lj@vSe*6KL%&R$lAP(a&RI4~#7f zibAK-ovA=yhZzN(bGNpkkV^`3J{0~N+SI+rchX@LPJadynuJCp7zs_P!#GJ-%^oyW zFgMpACN&!I+s5V3znheR;|v^ zS4^-V;Y8`J8|iD)tSXE}qttA-F>_QTKcBJJOoeexC1)J8BPNy3EB)45b6D4OdZYd0CzPIz`Xj<=df~xe_5^U7)j|YUY~`;+ zwAN_&lLs{Y2I2T1?sW9Aw;j{VGY;V{o69GiEckir)i;$x7E=XFzmZVnslwycYaL8> zra6q8OHitCyJn@)+3P*O-uI{Zi)k{X(2MeKLOz@oR$RS#uxW~zsOlVI1Js`uR0b|z z`eOP-9O>=%GS~WN+CYmOFR$ z>-7-txg0iW3_YNWAg>@W4dxc8v)`}1b!vbE=V0_Bmm4RiC9=a-rvk`_vO}aPj!mF) zhH*!SWZ*Fne`ANyX|+&V@4O`2;j~T23uAjtNvFX{^E8plenO;_;hbZTueLms(-jJo zBO+k66quif2i)4KJsM~ku@X)wDsV_8GuJ5GzotZ|(%Nw9sObW!6Fo6Oztayv`os4R z^Lhhq(@<$z75r72HLQN^bY(w5LS*th8swqthvqvwJ9&d68*O`m(Wk-13bkpvJ2mrU zh#R>4=xCd2ZyN9{HVqApJ>HzGUR5uGG%%3mRp4%(MS3P2VFF5f*=$(uSewDDXQpE# z+hn?wc>=C|Fb(THbkocl z-+p^dVA%9FqNoF_#rfkXoPW{8TlUsio8BRqKzA6eK(ZOygep!ljwfd}G1@X&gWtiq zBjP=7B$QZVkkkW|R6=#QwojXi*1E4r+t!=D&opCjG|HHn7tz~cj<_Ba8Y1U#+IK~n zVcmC1>CapL#Cws#pMdb=;NWO|9aS61VJPc4cc~f^P8QH@%ENB(6%lSIxGy{ z?IG|SdeZ4UD^TOneO!iWe8fEGZ93!HlN!7Hgy^j(z9Nnfm)i3vRYFy|omX8$YfU%% z$)`krQYq0FtTb6Di?2vBzEOfV%k{>r*&lGWKvk_h(*bz2m-{$m?NuUr6xv4?eg^h4 zF9IUltoat1QWh9ZBi%rE7D|g47E`rUeIqHR3ooL5mBISiLX%azI4cDjVaGbowluDr zaRRUL?Au8u?2Z`E$P|n~lVbWr=>R zd^-^}8t&x`HRO%^2Y;CBqs^k6W9RMO$&VxV-Fga7$iBO1-sYb1gX{ihM$`As85Mr# zctt5jWwbDA{zZL{t(JoLW9qSRP{iB|@Y9iY=dG5Na9H%(My>pXKhCAI8Eo?D_^b|& z#IpcnYLKmciUSNHux^G=<~+Q@1AWE?&!-5?a-Nmkk*9CU&v>ln^`ijB%rAuH2HvqV z3Uu`}_Ujn*U-w1$Iwo-nd~FC6UP{j5cb!o9N7|LNEy(NEnL&RDGsNQNJM%9r4B+o4 z?~BgoJ+r*dfb;eMM(A92WE>;ro=}`*(k@qjo14yCdQx}BcoJNQ z|M^D>xgw2u19^w`1!603pgWBd49UYB_Q9b3euggki`lm3CVRX2!&+8z$IfD2`SebF7hr4d#11 z4r?Q5e52V8WoDlxcwCHe5rtGSZ?=Cg=j2^NB1a8xq*tn{t1%e-p4p9 zB9Dq`oX!=g`l4ngQ=jRKlLs5@Z{@9&n$g28yob_v?U6@2EE*sO-#v10AZQVeq!X`* z*Un$I0B7`NyBu5eyX`jPk3r+RWv z%s6*cqPN972eC-Zx<~}vZd?gy9W_TyS`)TIxFum%gT&{dXVU}nX=g_%(e~w$_t&(> z3J&aza=2sP&r^VkEP9a;{osr{V1KIw$z7rU8y1_{jo*B0 zDS2HYsBvEr9FEcUfx8^;g7ma+SEW#6BH#3)z^c%JX1R{|{(!n$*kkgJ6a*Yz_WXUR zP{wFneiHo*kTlYCPxflXXEos6{k_hi$8JSjP=XvlU*@4S;xv73sawD`)x7i4nDTun z4$Mn~GWW%QjkFW*QLq+b^En9OPP%HL@jJ`qXa876z1_dZH6IppcEg931H&o-{^Cld z*g@%KjoxLDEv^5*x4=;izc@aO*Y^C_G{UdTQ`?e`@ZzE4iC)epV}FE>k!R468RO4)zT=C{`nAJ7BWuR6GYesHT|Cv$fcOHAf4E_yI-|KbsEHgIcpjV#{VPuh1e^ zp^g6P@scKSr^NAlgKSk;lf}xj`nKA0`2}hxs@=lBDAy~9b`+i7mYCa@s(Ncz=-bd_ z9T|MwNowOa0PUP)z2$Xyx{iMZKn#dd$7=ZM_tjY&_IjZ!8GN|H#Ygxmy1h!mTCF&V zJCU{c60cZKQG2h%(_m z)Hxs0-pTyFY85+b_40bEo-vxX*e1^@D_X(0E-Eb?yBdQkD5}txI+OMq00{YuZkuBdVWN&GE!(Y9dHKdu^8mLA)g zakecM?uvocil-X_GXrJE|IlwLGwO>NxyA3GU8yyU359|^XnmK{mArPMy6E2fzw>=f zWH4yG0V7h1@SGr*+F$-a@_Fb!q#zt-clx!AdwIGF6`w)iFO&C7BWN(Om?)pR@=1R&o|ofNV78$i*9uCC&qd z}q&$u+yQ%C%Kg%#)zjndhDF-Fp3&4fYtn(r;$ z_9B_G-&^CxQ_+id(li{-IgV9oSFLQTg~xsG{>i5u>V3W=l!LK_deSMEiD>fcGflmi zC!&5|ItaL@aq#P|;sBjh2Z*q*rPf}iZhQm-$O9{^Z= z*QjcJjhd8K;^omi@hgf8(-b?f9~9B;wI= zy^AF1d?8}2HxFr#HR3&+DBNLorgAgStqg&>pHWvkTlv}Q4meix%4EZCKFV4=_6+H0 zp=?TvUxl(m`0`@%iW_PLnBtz}U!x!|KFlkJEF8=_#Y+tGuwki+F;lD+0n*FVb$#TE zRVlnqQgNGc$j@IYGdEj4#-ZZ0>F-^_&j4Fs{^AOU)Cm;VNPT`T;12w_d35-LQC^OR zoPlwyR4aHmO~|vuyVdegZ*nP5Qij^1dg2(t#OuCbOXxb3!XY?H-IGX|a;&@%e~5Sk z6BccAKjAnhto(-C_K)7USnt8xVDQ}qX+L(Jkyt${@SYi!UH_&Q_9l15EZ1>@sr9m9 zb?+(kK2G2j{(kIq{rcAqH5aerrPtH9wZ@;F+)D(e5c4mPg!cy@zMDBRbjAy;Dx5H_`! z3;IU&mAZeV(8DH;Hdw3g7!_ z)OVq@C!7O#G}+1&>MJ8Ks_3GJLMMYU)F0nB{87PbNfg)e;|a~@x5ziarb>TWD0~@B z13ppdtM>qNCFQ<7r1=U)1dfG%1-p4{8=uPNxb47JKV?i^vK%y|^<#cfT1g?@@_!T5 z{9$I8%T@%gXnZwJVtvJ}YlbvMJ@t?vz%#%zE8S(;+(upV6dw4en|%BGipg*YN_h-z z>I56z!yd@uqYX&q^H?txc@bV5XMR<$-OS>ypg}%IPMQ9;g-4F5Yxz9Q0Q&(@Vv}d9 zlbcpp4x5tq{hGKR$(>$V+C4x3^S{)_A=wKPHQZPB5G91tO7`J~9{~xgMAo_A;*xoL`fA9T!64K|~LsYvbx1T$CeeCvO%VOyN z5JTMtpa7ifvfw9c2F|1e^&+!tdz7O&EZXJ0_T0d>)@SyiGK=`t`Y=&kG`hA;e@zTa zPRmaIj;E@nj=vwL8CHbZ5EA}$DF9rR>7Fa&!oBvp2;(-^NmZTIf|#WvoSNUE_Fuip zoJgrCpHR)f)|0Jg!Tr9~z;B6@Bpu-mP|aq?tGcm)FWA3l4!?Ke^>!Huc$iZ=43f4W zAo)s|j}HIHmsaCMUK>#yfaq5>(5eW5*fwsow>k^*w9p(3)?mX`?n z_U7~(BSA{169%(kon^&QbhHod9gX+LJ<+ES@xF~DnX=|h!}c_lCbrKl=08S@QFNFH z-!G2eG38K$uo?#hvk^-hA?0B}Big2C;A)w*27NRgye-kbCSB9fXJ&fJ`Ww08GubivTRsJ8YYcWZr8_+yvtU z&*DwQMg-o{EvPV;JNzpJFoP^7kI6mH>kBzglisz01%Ah1U!C)7)N{EP<&P7X@A6(B z32HXo^fEG6cNF&y>TmQKutON4yDf(k$mf^Wf&7j*~WDAW(Mx&qm!)uXH z)H|t*;NTOz%G<7>MjRc(v_$uRQ{!~#D{@#*(P6w9RVG`oSB&lmeQ--{s;u;FyKhoTf^!A53GhM(mLN#brpP zW!ODl$$TyTj<{UhrF{fn@#ICFRirXF>f4Xi2Ux>r{Zp?hS{U&6JmN2dg!_k;syH1> zV2$d7G3TW27j>LF-lK%d#nRn3V+|Tq2=#3ZxZ8e_xM4eU>MfFny6R`r@cb;RQE#jY zO$t<02{ z0P4pn?Iy8=2PZ-RHZ}4@_)NC#ITcV`D4%oBsKTq_B|nKjIBVlWjG)YRJW_AcYutY3 z!>(-5C#`I6EH#Rnv#DQ^d>4D1oh)Ot%LNtmDsTmBGkxQK#^vkewJ?HrTfsEze?q* zGWq-s#k-&yBW+cerXim13WY33E$pyRv>~(C)k{v4IX1UkF}kSr1F9`&>yM%vF%>59Vs|Y&;WQGq^v|rD*sN3j|cr@aPu>&dKe`=W4fQ}$6X!{4$mxh}QaGyvC?zvbjXX>x#sV2CdxoQNtDRJ>%wWN1gcwr->H z4LKRD@BDX*v#p=YIU-e_cX&(v3`oDpSwnDiH#SaV1&g1HMq}I!4&FL@>%n&w_bz?GuN!fvgIoL6QH_;ZXC3ZhbqT&hC*`fweFABW0KcH-K$CBgH^&_jW#B3EUqOx>PZ)FrS?mtXGhJC zap<$y%^%Q@tye7Di%H>pYPIk`wkt}Vb;oH9vLPe+@q>tpPx{uu(!B4Kt=$svmOa=s z&%X;z*=Xc)0tz*Z-RMJqV+JIm+A!tjfPK%Q!g#pxM)E+ZN}TA)*Vuz|bli_~k;Q&_ z)PoTUf^X4eD=SE8H!MXmsoX(4Xm5$tqi*jk|EjPfwQV5Ljri^@6Jf`TI55AL&z8e{ z`px6|=RRMioX;UDrwNJqo5X9r0!h%H?sSijf>4^b5SJLq?}ftpT1=|U@B+R^0%|Y7 z__FjgTi%a=`HSc%&=`)B-01DDQ{h6Dd8$%dC|AO0O_naZf6x2UKC*SU36C)c{V6_? z=-Y3==Xed%nI9`Rg`jB#8xx}!`WIQH z+Jcw%dasT%CWL7HBP}ieAa5Ryb;)|#$nhS|wkGiq*B8EK6*-|frOsbOFNtI#k@zX| z?0k1ZSFE935}@SNLi-w`5!5g`AS*rYmi{_%{X%hK5WIGn)2rs=KAns!e{i=?)hQ zRo3h%kVh)%j70S=4sg->sd_t}grQ)WHMx|qEAIl%Dnow zeArPqWbyrr^5rLo_t$Cxc3C)DvY1zgHH$j>mPj472_q<11iHd*?}to+7?$BbqLXQI z(V_1}qHTkNG=HIz4nt};T~3lW8i&*b+2 zQ|IX6LtfDGNj6Y**o74Z0w-^me&2buZwDMJSJ;UYq}UY9`5djuM>*I;yo^;<$d9HZ zKl8{y$OVnC(J1lBzJe!(@H%x(^Iv|LN!d%fyd}-XWqOYq5hSWfi#9Au)#X~my9R6` zZM(=P!dbA+)~j&!#Mc3@A^3j;d$SIH@?a6O;p8@kbaGz}*6bIk+$i1*p<)xIfyM@I z#*;dvse*=zSo_Af&3YACIyvg3SfgC7#ZI96%@bOcC$!{1vMxR1mf3Pc2LNHfw>YsD zlpC_V8^8%*j+qGXsgu3xU7-`3pH~&Zi!Y3RINLulC{Z4`&8)FjWD&bbu=ce80@znA z{iROy1cCxTwq2|%oH-Nj*i2nsP!@;x6;d@S43ZZLx$hGNLt`$Jb~LHMbylN}y8SQ` z)v*s#=(`S+4f;HuI%~NQ{9_@h4o^I5L49H11)W3h$0Rzf(%1@bxB7KZaWb0zE_LO% zB2fS)EyBzCB?zmiOKe>YcF4NepC6dj4$8ghO5g(*r*OS@Zqm9>)U0ekwVwc5qM; zEr$#aHUwDBat7`Gl-WdCSaT;GV1p6?9?GgZY;(~Clxub3sRzcOL5~t*EQm2JU`@I; z+>Z1XrMgA;5&4n$7*y^;@;JS3rivD%4Cun9ocZjH+w--oDnk{}1o-{K>5aN%7*>s9 zJ~FhH>k)rz(HK`t&@y+?!eo7#@X!R6J6jaFM^Tt5xBs2bg)E!dnld>qH%eDe9}o$p zKfg}Tby>2_!EO!xRXYel!oIIoM}dnBsFN{&?Pt(Y~s3+6$vSc7Zk+W7_mc#_bLP8_LSc zz>e3S>?k%oVKhSPypm!DMJ~aDUsKcyWSUl2n(azv%4>4Sgrp%AQ0XK*f(lA=YQ^hi zwL|xAO~G)3Lm)RPHwoiUMuilL3v+DcTwJp(K&}PVCi|)8Sv9xBd2HmZxK6v1ChedXYG8@2 z-_6Q($4*V=b~nEw<>q(FVwF^h6XDM#DpRffeDZ9}K5sqftA?h;2ZOtU@Exj%IdcZ93RW|=;lW<{$tohyw0|E@s|Nrq&SxB?Ggs{uz(IJsAZDL zBni6iVNd%FYin8gY+xzM1^+3JS%OxEw%+HGqKeRJB*O&LZ%{nYXZJ+>db*!23Ii^_ zz$cF~^jpI`;`E2p>dLo8wu%#ou52p9cnX)%UvETwUa*K2S=FgmQ7>a}OKsQ$_oppd ze&=|L$ZJ4n-it*f;coDSzWZ-3;nc)w3-3DSCl9I#jqSJp>iUC6s6^=hWNe%ysAQ58 zCHyK!MM|i=q{uFIW^2eKD|)rH@hs!TNMmZ&)`Yy%|Iox9j_UFh?v?*CTr1BAI0$BH zp8_M~_ZPx@FlR$^{EqjWy*&NNMDskGuIu>1I;LyCvXGt_1iXKrG)V9edOFJg)XkHf_`n_YGcTE?$=SH*>61kD>xD@uqcIgYvlY7?_|9qXC5?7k&xGV2* zhGwXrdb8e{e5XmnbB@w}XvhY5fXK0axZq^%t6_D#MKDY%u$@=+^&7(_b*mI?5f#@@ zSuXkS{7J>^0t`OI{hKgCvnJ6i9zXMp>f>|j;W%1v<)|e7;Z33BT_2%)QFluzg{$l{ ze@9ud>cElk4wk;+$lAxU>JBe%+B>}PAN15HyzoCW&+zh#;%7dqF)bMGR7VXV?E^^aOWj~XdC%!Hc12cW;%wDRcj;T?2OpQ0xoHv z=>aCG%Yol;X8Zv0&{t6Xrb0&Q@-NN3pjd2ML6!@f+&r_sxRnSLzgM`tdab)@q1Wxl z{wU@1$i3%%WDY+^TTZ2&jFGml_ZIsoPcJ@r9U$_*H0f_h2+i06tWVZk4l3&~4S3h) zb$X*Pe5!L_agwO{0jTD8FQ-%}XU0hGYY1qqcwW3!9)px!Rf$ zH3r2CUWcVk2E%I3p0n$h5bGMg?h2ifGqWP8=fO9R--;CMEBY;O=}z$x*kg=(&XL;r zbruLWj9jtfI`K|9c}#%ebTBF=9vO*2PFal2l*J^K=k64edyEBX%ET0EpUuVI^6Uf4 zX2Bf`@$RS#k4~4#rPAXGy<*1ufi)~B>)DJl6wCt=0mN6Js1nbk>vzjjLQZ{xc$1<9 zk&>uIEEStJMue150YN$?K5I7#yeLuv@~ENcn;tLeHh-lD5DWEoUt)SCf|&tg1)8He z4<=hm{zRzzB$y8SBz9dxU`SVR&eOe$0c|3aky#J!CJq-b^17)@B#(?bfw{Q^4Zl19 z27-=pbu`T&-a$u`STy_#u}BujU~R@GiWyT|FUh`OEhCFtsd1!ST1Lz^G~?LFZ+(;* z=V~}hdxpM;?jXU2MFo7GaP?mw5}C?y_?kNSvyq+eKLD>!C@?!)k6J!MV%cqBoSutC zSpa|N7l85%8)bHz~Kb8p*Pua~Nlf#`<}_LJZ0QEC4G2 z3)L$n<$!XXpSYyP$Z28Sm~{9UpseQ@QzWe_W~4QTuN`Q(?{!*mv=*Dhc|vB9Hc7Uq z;^4YWC#0%W(Z=j7eXP_AOPGSTCm|2+Tn`NPf7Hba zx~Nh#A!)q1AHNv<&eGyqU1_l4--I!8v_TSfpYD%6b9{sE-1d`2amMVT23wU5Jy({z ze{T3RI>ZS8u;AaI=m-pW_hUD)dYB&5ykS*C7?>NuAg>C|V?M=$ZDjJ#pg9xYrsds< z&j4_1ei!|@BH_pAR}LIgLY#U9{Q@}L7ZHK`r9b~gA``M0Bx=0f$qrmenPt|$UTRuoD_4aHd-K?PTt!TL zRi#s$Jb(dLm$Pgl;=_EKC~(4seuR8E6TIz;h3-!&uj{wQQj1oqQ_-UA4jq1rGiIq( zp<^;2zLJyN1}x=qlwk8kgXYJyViw+<4d!bjE91sX{B}Onc)zPtK`P;?d#xM~LO)jJ z?45jiybHIhN?gxaK$X{Kg5w790&S2o2;<+y@qjKqX4@FSOZYTVh`#UQ^0x+jMNC@p z=NQ(Gkj-=kc5+*dP^G5wEc>0?U&i`s%DA-`ga5r)h<_6Msg~wunN97O)Tjh7*Qm~J z_GN`J-Y1OGTzKRoH;~{$)VzK}m{h?}0mdc!iNW@mOC}}My8%4(*p5lp zTBjFFY8LYv6;UVgefv)<@T;BIwkG_t;&bk^=JoW2ds5`v=#F>)Uq8D^)$~c=ga+K1 z&R;lyw9H3ob625a0xU(>tV1B5>r134ySlp$zE;oP$(Us!6#Er^45k=~pAy#lpZj`+ z8ixo*-!mISsg$!Jv-$1T`uoVHS9^RCi(Nmk})I-X$@JS$w7AvGeuO2ov3E~qDXr&13w-HT)-sIC0$Ts|!@ zm%ZxcdL{(F3Zjoiw5&JHgI9{Nvfp??e@Wboc-v81P61CSdR;R8t_Qd8j zQc-^b4IwM9(P81_`1M*t0iQmTwb{+d-{4xq zY`eyEsMGYc=E6e`S+?K$X?3M#1u%_X5+!_#Ed_m((li%z5~_5Q4U%)V7%IMz*L9gE zNU9y5mk0-NLvhR9jmF-vBLE~bP(;;%H7akdKn}&)nP3pJ{TfK#F|mlAatw;E6Ao(g zAV7rO8zIP+3P4eyuOf_g)qLd-MzROZ_(-*2TsME@o z|3sow73;Y4Z2E{+jR@m)Ppd(XBL+9$6I%;5`BWbyV4oB$;8{sNhwbsr)nXfVgl<`> z8O1O%7!M^K6qD%ybj&wsPFk&ChJU)8+EFVKNMp6)Z&GQWqQyV#f5Y}6;uD|&b7RNf zY6aoW_RG8Pj+vlr0t6=K&}6~w&|RI%j#tJ21i^s=gbtzwea~i9x>WebQi#O!1cc{b zv!8h}I~2-6M`p7TM~O!ej}c#AUo*%@Od5&}r76dAc^9|TMhA(8O3^^jh4UQjleaEE z*Ro!>MWg9TA*?oWRR;|1zdR#?9!;(|8V93X3xPc4?g{C%e$S|&j7?i@mzfHK5+8Dh z6EtJwc~i%5MO9_5CVe{EtuRCLZx=P$#aYa5s>++r2PqYQb9WzlkUF{7(2eCNL0+il z+txHU07%QnY$97^9o08WY}(q|l=e)b34nbTvjQR?V44?hLYHka@55SfC)^Y*CFBIP z%oX7Su-OgX=>h7wh$-GdvlLRSl|Io{gnA#Rm*lu)xAkSVJKJy|c3+BDQj|dnGN|L9g%1q@p(IeLa@IY}1c4;K ztLSHD;u9JS62P3-hwgpi#y>h=O_Q;lur7Y60ArBILizw+uw68!JITSmQ!aSLi`rp- z@;xR&r^-!f`ENDSjl;m-$alH@v5jJ3a{X)&Ccx9izMI8G zw;0P+R|!Bk{$`jU5OToK;rtsw_x{tVRVQQ!htJ*FC{lkSP6aIu39XPLmk18QpaOgW zIJdp~_(;tY%JY(VsC6{gEa`V_HAbL{KTpR2P$!ZOVBexGFKU+g4k4Tw(z?OpMt6|$ zp>g@HBQC!=zHP&xQ*w?&$3^$%GE^Tz=^o{ZMaSwVKEHXM^V}xx_nN#VC*cf9#v9Lh z6ekVSx>*XkC0%c|P_hU+gZA|k*8*eVX6A=)seR$%@}j~827i4X#QgUZuJ(f#oj}HJ z8rN+ zichawSQy+9b1kktu8lB%ipkS|6D3Yur+JFU9@?4higtrc*d!X9<$iVtaiK83%>vev zJEer70Py4S6Vm-Ay#=gyVnn?+GNo6iN?RM3=R07efAvVD^%Jd-gl00)dvgm#N`6D% zPyXq``E3od`2;Y@U$tph^{!j4vpa_4d^Qu)pp4cCLzb;QT5rxN9k`xF(MY4y>OKd4 zQox;TUW`|Hz>sk9`-R2ccca1yr~$cioLjhnO6wgm%&9% ze+qXQqagbj;u~e^ztaE#6B-Gj4Ej*4BvP`nnkXjD6_t1nbKeegXbqsKKtN^Wv<*G} zyT?cWJmh{Crx-D2L2R0G*Yc{c03|l{{8OWitU;$|Z zz_VB!OLTH!Uw8M1A%iJl);d=0!YrmaM(V=iz;-57j*!WRCOvpni9@(^@IOL+Vgu0w z?wk(#nR=Pq^=fP>Lf*HvW>-^VI*fn>o7WdeLKWT;#?G z+?9S7W^as;S^bGi%?3v=2fwNuFym4Yc0gnKgu72HdRDXdcSkIp(xcp)?O``(JCw_> zMxj(pi?-t))`=lgs3>f$KYJ2dwLmIH`*EVnncOaFG@Ds~9KRjHJL`&~UhIG;$5|@!K}7 zjcCgLU$|~za~#_-yyhIOqKjmKC;0|2JCD=f1uR-S{&z`LKcam9&iJ_ z{GNpvB06Jh53iFOPJ_C0jn3s-xRDQ8ja>A6#XvX*L)9RM>WA-~X{(XxqLmB>aU(oF z$rQxntSZ-HW{KqSxd4X!#-_xJ#FJ5*>PcU~BtQ_I{>A2%?G< zPQ^Shu&dCU5J5<6GRK+^#a#$zfFd*C^ua221@`(cOTSv3IC z_Lm_{h}N2dF4|+FBugj9O_bR}#SIlo4+6ZZtREm%a6ybKQ-jlfDrbU|Lt~wg<^qnf z9l|i%w40sju_8k6?e~eKm?l=k4(40n^|6je zzB#l<)DW2$4SBxFq=1;mn(gDqURj2gj-4hVezIc?w<4Dgqp4BqeF zuzavZ!7HF~4J!(BA5xIvv_n0xD2_^9xf}>AfDN%Gzx!?T?)Qd&`5CjAtNiz*WX+~_ zqy<2OXJWEja`{J~MXB8a3!?IRG6@Z!F}xAdWq_a?#OTym!x&3hYf+`p3BM*C!#sp< z{CsgK2nD4^nK@6?WIl~m0>643Ep1)Ne%@{~-u-wAj(;;^^TTfB?x?Z>t_i2+EiD;* zUjgSD1ztvMPxpHsjS_sY#+I)e-(06pNO@-1q2f!RnN|G)<(D>IZqKK!&bTYVIswx-q_}$y<_Mx(Ea&n<-FZfB`m&7TikKfDGrM+s=W;nN zz!O?VAQ1*L-6OAGfhr)OFxq}&KfA@)?*$tkb2n8A8n)m4aUK<+b?yuc;f|YTcg@T(68kAp(1apOUGqJ?aU4pWbT*O)_!OAZ4KYI1(xQ+;OKCTi9#H? zM2L{{YJuHZIB8P)m2}&8P!J30VK$kUI&jK-7%2O?BXJ$~Sx$=x_NvL-msGRD4uF?&sWta9{4)xqS0Fx_8G-&!su-2XU)Bck@TayqiJL3J2oR zf(i7`6Z6j17ra7Dlo29#9`i^|Dv(ojUV1iWt{ahA?-TXI$$XiPJv9_f)j=?WMq7=-eCe$!eRC5d! zE-!ZDESZ4aYv$m^Wb5$56YJmo_*b7M8yt%6g*Jn3n6dJZlm1t-raws4)U?*f-vfyx zq2u)CCk&BucQGaio>{E5aPlJP&b_`J^&ipe!opJ-@#b0bTzxb&=Q-)cLk(O1qU>`R z#42h*@H-?Jn1i6}{~i8G?yV9ESreMD6&~YnzV*wV8-)NY`OO&V?Q~=mNox<;E#*#? zZ_uGq{-pFJb#E1d$BV`R(hg#Rb&2bn91$V^SKcxIo%XIcSxBgU0VY>8WgOSG^Nqu1 zjSfjth|iL6xh2C)<#0INWN|d`r2KjkRM_SaOoFuht34;3{Anv^JLJ(0H?;FPFn~mL zw`!Wk`gz=-JGJvEXv_`bUCOb@wsv0%f1DoOvo~;1VHtg|+#?F>$jVMW!aZ}&>2O*F zI?&b8cfC8C`6ZDv&@Qacj?)xCR`*FfG!~EJX@&5wIS+p5zKHnxEkQz5e|MGuD3ddr zEla#RAoVtSy|~lrM308?e@N+6epI+x751tL==I##??3E8?hLdeS6ljKpU=i+vMq;= zInd~mWFk;jqWb5i zCP` z4{+kG=sK^@%jtwQS7LqQ-wLVKDMeG(z)7OSs>FMz_lVN_v;zZ@g+x?1GNRkx=Talr_+@+UAjNf$QlY_ldsK)nav}K9;e-X?16?)weoTrK)4sHHnq>v z6wr=X`JIpjiuY%v)4kKgB`fTuFi-Gf z?4RJc(p~o4Onh)D+DEa737odRS47Sv0U9V4HiEcA64bYE3z~t{ z0mM!bZ}l$~{gw*M@MCzeqe!W=5$S7Fd}fo2U#*L1zlKTB{(u7=)QW4$SvUqI9#ei8 znPZ8EmFA=bo#q(pdidLl6#EX-t9tQx{k&+lw1)`fTFBmC{BR1fvdHhMwHWy(`k{h= zAv%U(-ha1tmZkpf0`eJhmDjLS(mz$SJXlWw`k`+fLiet`G#Bq)e}UQN6<<;)uKY(Y zR@tDdU{g#BXs1{9T$@eZ;^O6GrDr}C=HpY}X$GqV`uz7bttuDS=gBD)5w_twuEFgdYJ zbB?~!%}*RaJ-*Gor!kMaD{O}ldaD~H(ZVPTqj^H_(M7C|8o)j2|EC@z*oK_8-BEL) zP}>!~A3JI~k30FH;=hns%YUmLo((3MVE0&^+N^I}g83cV8P!>ys|4OTxh_sHEP32J zxEfrAF%>GBj|dia$siE~qtYumrZK<8Kc&m{aseeMp^!ITz^tqY$f(GjMPx04(`4Qh z`EmvYy&v}|K7I$N`@4oto)}U7ucRP&fKNCQ>0!_HU86EZq@11JN1pgrEUbxn%95Sl zACqD>y|=;tT^~=?0;*Vkb=J(tmn^O}BR_5XQXc<~89G3)_SwtzGSg~jDxE$yN30lP zTGKBTwP+ja5`>J=ML0)|lU{9CNr*6%ocQa#a1N=x8Parl`}JX$ik zb}gPO+9j-#c9D`21flD-a1y>{Atf4{jU1)oM3lzVL{Wd3Fteqy-RpY4l`~JfV|}P^ z$=_#zE$0MTF{XvH7ZCVB^OBVIhH~9LUhKIW(?d?d?RQJ;2eMHeNu<{s813+w5-Ix2 z)%pDxO$s~NCDDyHBnW`^ev>Uq`41Xl{_<2QqDt8TvzKuGzdy?=Q%vv4oZuS)iGR#S zkf`~Ngb7mm8F$y{gMXE$*R=&~2_SH1)B%f>7>L!MCdqv-)Li?$QUCT!a2L$aj-M9Etfjch|>G#-s`#*lXd9Rqprb z4v5B@vZbFte~uZZ*sBs=bIrN-4f35yki0BB@y zA>n)v$%2jsZ=Kh$ET9tG@26O7HeMz^2#(RTZhn<)wtUa?QSC5tR&SJ+qW$0vR@Iut z!tW}PHwOmE=+PqOiRtPl1}jpRhs{~L2(TDWSkJww|C<)2 zrS*w5Qm|JfFkReW^Xa9#@!cN>i-CwOH~3cv5Kv=bEZ&?DvlnGNcGy&hfJ1=NAw9x< zjilKRH8<8tOcT3CrvmSguA>M05C!{`+_87Lv{LlQG*zFq3q&h>Yq24V;_ix&j#7=Y z-=<&Ax0Uk59ZL1R%`DJgipQIcak+u>o1qhEehmI2QsFc=?E-EL)D^cvt(_iSQfy<_-K5!6RFsj*Z4W$-8KJSL4;m!K}H6} zc`!3ovg&6xV|~QQ50IY>%8x1_(wz|Y*^5ktvNog-w)unY@@h~$cg@AV+M6b* z=>%juL5=;&MrJIsERa3!?*Ji8?CAc(!Avu(yF2{~iNn&-<&D&=Biko-+OJ+g3eJF| z7nsX7IF&NJ@G46%_s{#Fy*9$t0@!N~uYsnIzAGHL>F);iJmVR?mS_~5Pmyl(S7Ygi zgzkwa6|XbS=pIqFkYXPpL2_mY`kizKS(vp9^!me@>Dk@->}6aM`BasuE{;E3oTzn; zR_5JW9+)lyM&BOnvH?hFc z|8(;CvFuG$dp7{v`K7+m{)YB><5>8%&Q=?rG=1uY$a(iLKl?mPvcCFs)%aoWbKw9X z=C7uBQ?rbV-HN^HQU2W`_}cH0c zZGDwO*&o)GAVpQF-r$sawQckDo0=f!r-Qd2Ol%j6zoR^IZc{E;yCkS>M+yk$GU2YL z?Y)*R{N8D$xyq#SK;Z9+VQ7@kI5;pO;M^rJhIQkZF4&Gks~h07LVI;Q)2z(2fOft8 zAk+(hI5{XYk=^E#F+c#QR~q&fZ-drlSV7W3cvJ0@*>%lEXtGFFlLzIkz1AFj@^ zHZ9~rL)1>B5Lx^b724!9X(D*t^jM%n5qNbhM8sR3`h0;Bwh4Eh-10`gQ?~l~Kz5*h z#WFDUT(TOM6VS%t@i&M|pTxjIQvN)A{*efkLij43(kXi3U)a3|0Y{r6hd~qMuF%Rb ztuoESML_uJfZR-ka>M@WEo%SD8756?6KlY@O2&laZMm+$xyvJ%I!U`WY)arzYl0(S zOTvHwX{1%^You7f%DQe{&d2`;9zo&06xDpODW-{2++fyal>TP1oBc?6wB!?!c*Z;j z+Sn9xHu~EvP4a+#{Y&$RVzyD&1X?t~&y-M1E8Z*qo6?B)V#GMl%<9K!q*Sw5)SK^T zzvEZY-z>xCuQhw#vcCC!W{QVJ$>@?SPMS>?wYa|BCLzC=X<0mfsoy(&ip^fgWViTU zew}k5=fFG80kvV)rC9m^z&-GbU-;}?`V!WRtY=wwVF|oW8|eqM0Zd02`wKdOG$(rd zHyhrIUtbz#&6*WH{_%Sa_^}B;YSbv5$Nie~VncS@*6jks4r#5|O|Dtj+X|7*aDV|e zTBU=ZVvB%{|8)l#`8e}Y;FB2ni$&|y8xeH2((yXTPXl| z#}T8^R>A$`UKlsl9K!}+(Oc_#zzYB%0Bk_71U^w7`q-0&R4-0O&_v&$zqEi zaRB%#bqoSZ5&(0YDGSgF-{GnGpEA%lzxj|JZi~l`y~1r1%R`h4Y?L8DCDI3&sxx`j zX5r2J`ST5|4j9ls+@dqo`5l4l=4}bL_Z+LhIq|qX$CbbPxY1+6$WbH1FMjc$X*eqI z75V|_I%#ifhCCz?5B`*EpQ}Oi;Bf#K$es0k_nzYdyx04Pg|X@{k#nre2Min_Il9v2 zdG@*I403T~!L7I45`HH+qMttx*tZH-~6_xdi^@dq3$03g2T z)kTGV4TS~d5`_Tz8^A4O7v&G!yFdNRGop`GY*R=w6#FacAX?4B`yoSy3Jg2$Hp_nJ zHOiBD`%`n~_&jU?^Ey4J9|mxoEnc}Th^GU^&zo+#$-gNl{Wnr=*=fqYnG6FC)As`C zp;$t@EDmC6A&?HVLk}`EbH)t!3jnv2`DPvAK_C8#lyIUu?!v3hF6i%e?b3PXD#IgPBH+2w85z7v^}t!^bH#Vw zIjZ`{H9F^h)4mx0Ccb zLd#W>r7i+`AA9VvqI95;`2>OQ^gG^*brttmO0>6LE(N7--Fm7mT%~$azoGI|*JH1K<}$3&tzf%$1cLv}fJfe5$UhQvWnbig?SMCqV9&E!*sQqJ!cce(R9N z)k7-R4)u8>Wcgn!MS!(d6yaQW6aeNt^_1H&-W6yc)LVtdM-<8!Coxu_E!5XXZywas zI**?LAY1;>%AN{w$| z9n3Fg+%Us^5Ay_+0gz4FA9JkQ5gN5D##jW$NdjFopZK?j78L;BELgtvt#8>))Yvhj!e>AGSq(&M zz4)fHW5y1F_%CQUrtp(u*;CF^uupg}h%CvMEX_1AwL?)jixjA+6WN1{Tkv%2s^ zPH%8d$tOSgNoy=W_+XseGZ?0jCVc#6a`rcW^EcrKKlnj-L9TKdQu$J3eKU;mI*TE+ z81J~_j_^l+^hb7S_osjQr>dhk(c+cjv|Iblz19Mg+`I3-+lvTXjj=eGGG(gyo6ejn zelO)yT(0yymGlg&JieCIRZ8QM{Z>Ws5B@k%aq0S!EmTf;&VhG>1GJs;aQt9hSi53t z7&fYF=v~!TPRa#jhg$WD+R#yyvNF!ild=&T7COhfyln`>#&!*V_rLx`%ei)ndswc{ zbyjAh&gv_v^O;x2brv`qWuvMt^I+_rZQ$Rd_z5!`>EF6 zYH^SFTBSQJ-Z@!tKL~v>crkdoevssNK_AZ7Kk;*`=nCZmQJQ3Mrg9;@) zHWh8@(3C>a6>UlHN_Gjc9*Q385?(}}C+;+V4u|=)4BRv4m42*?mNANdL%-f=nGnBu zq>qcuE7^7N+v&PB`qQ)YO9U~cqKI#k%M>~LW&=FdT}CALl@RH&!Q*Fz zHW^={pJ1ahS^8ynGagYmbz|x?*<9iM^gMp2-`VZ_E9XGYfeXR`Kt?vRv1np#?e(4- z@(GUvC1I^Lai?E@y*E|?@Bm8HK;5^}zs8ms`$~S>+EtXXIf^AYN=VmeL-;0vmTd52 zHT#6l6{npuSD|0PnviohH_9T=XOAj>z!_YL0-WuXi`Db7|;~ffj8#isV>s!T)FBkpgUDAPHSev0#0Qkh7 z1e@{n$$(DH2qYkiqoa2b1Yl^9=do*`x@8gSK{G#%~Wpt_C7Oz>o#_v-EB*5Q^ z=Pp;QefZvN&Z#(7jMF<iW?;?l;8e zIFH3bai87g(uP+lFFmr%A;SdZgX{Zby$P@W_>VthOMTL(o^bul`Ni&MOuS#S%XYwB z+RXK8+c({KlVy~1m>+%YQCVE>H(>SrbI<$CP}w7-?0{g9 ziv_5U9}q}J8z+bb6x?UTzasDypzHHr_=4LdbielMYwmNIyR!%P{0q;A+i$x)d{v$> zDKFNS$QEs~UhV&(Up{2zq(A=5XKcKJ0?2bJH;Nfp)q1Z~Y0>_d>K?~b&_3?E>n^uh zK=^-CU%OA95&-#-CDJYqv@z<5{)+w(_uGKzH_ng`R4LG;u?Bgk%$ED&%(H9O0@MRXdJNHCC>E{6PqLI=p-zkM zEmZ%EQ59!rqv(Qx4}B)bfb5k)jw?#E@*Zu2eQD;=Dd71803Ai2PpPgMa~NY^lPmz{ z6OdzM6y+KM=|CH4)9znYT)bJKr~rsgU-_mKxB$L4s=q-&h%~5gXv5=8#nA5 z)^D(K6E4M{6A$1eGB{)AjPRikf7t2Mzp{^x{Bt(9>ri7waiAZgUW)^LnfWdH*nfZS zxo54w_knvpU~dN~)8TFAWqq)a#(M{R0*pn5SFc`e#hq__;~V1VaVshTz*kjOWu*^c zqs}zvXpleA@u~Fj0JpST!0j7vy3z9sC|xfeQwGY++yyzAIcuh$!*6(xlAAbcZy(4L zH1C#@3hn2f58mUkg0>4_j`GV?$tf~J9im*vT!C~{%?>4!732&rH(2?VlRN`s>uP@q7G1n&@pH^q}@pPg?HJ;)f!74QGR2UKVB zh@!rLK9jOBUt{biuVDrInXAAE7Q_Y3Sc$A5Ru>f--8<2)R7}l)>-6{oB9wLhFPEK#hRzgwcZh z<~P47*I6UNU;NcydN3J2d|3GQ|MhLVI{W*-|9hVgx{)f2@U5TmUo4tFEq&;PZ_FaGdGz068 z$i3B*8UPPz0mVX_I1Hkci-k31XCgvcY#dM~mtPBKo|0qPyS!e!KMf+0T9^ zH(HZCVfoRIe&j`?(`C^u-lg{#oRcyF`6Rw+dgnC#N9p@r^3exgFkxrn74z1_N`rlc z(qiHegW?*IYD(skxys6$=!GwJS_E;95alOW#xpsG2W&XNF=QylaI}l~hg_q~MVT*} z{FYEB0u{@ShRIXM2?RVK4e*1ZRtC6rQbcVy5f{bY9H0;_+V4dyM4r`qnFEq@T=sEZ zBO0)U(9-(b0Hb7)!@3P_YlEodQ0P6VG<@u{GsD%>s>89eJ)y4Th`Wf`)2PqWKcpB# z$WlOSf#%Y|)g9zoeVyf4{f@xz7`UIdw4&7eeLrNehb5~Px($_~tiEelzHoo|@&Ec= z*t1<3oWNz6(k|+w&IJIcABg>``cCx$w4E|}BcXp}A(j@LE@N@K5-;6i6^Aj5KA4RT zzUhPMbLeO3Pq>c#thk`Dgg%H34-#P9U|g})u6~mrV~$phV!de4*c*raIIfWnUPtP+ zIpZ-v;|vKks^4b(DOLRzEPyEsbclF1YoV9%hk&v|p={Y^0E5$C#&k zP9)wcyvI*RQ~Fi1hWNxMKH>BB)@u`hu`QLE@>gh4irYLkBFO_D@NO)39G}R8GLfnk zDflh<;C;qvZ)Vd^*J=JC`T-^=v(IA`UmLWEic3(t0eAXYA(Wz|$yRN>WKqOs6q_WB z!JLJP5*wRjjJa57#lXAqefUHmAI1>o1MOt}!X|?2SBQ6^OV@8h&-~I0Q z1%zlLNb#Tp;1!u9jkK9kriFakT=9LS&IZ5BsQBLOm;AwbWRy)^JuIBt=X>G<^+cV< zdXZ+l>5Q&Em89DNX%Wvnq0SZRYt?6{%oXx-1MR#=9l9P>x0Y$$=NZ@BkF-aAvT+3s zlo8i;#KApgliL1oOL(YLqfdjNF`cb5p{^M;y?bQ7`eU~04DW}a7=+C@%(lzna88{v8yRXsj z;yx$E*Nc9iK82)+Dr(XD}Y{ zQXC^9IKW&dt&d~!kvF7a8c0{y26$~Ezg_hMDVav5OJ7*!n7xX@9`YRr3Z15Q0AS#rA2k?uuC zc|O4$6U$7WE6N-QS`|o>d8^C7HT>0m)53G5LEJ)o(&Urf=y{TZ#K-i$ z%gXx-DGqs?hIEhL`Uj{>+2FnT;3w|_g*mA(EXNy`l8NJ;=xi8`3Hqqd`jN4hC1_nn8XDGO!ieP~0uqFMet zmkf{>`-xVbphiTG({T>4P`^b>vHZCnv-{LCR;T2HA_cPOd?=&dOV{uQIb#1UrXTr0 zF`*M4Fn@$+w8dt$k`_UElAq(BOm-EAGMNt1l4wnJ>vTzkd_^-f5w}VH^dOQ(jxms? zKI99p07_$>#`2Mz^U*i2o|JY)^!zpBOL`~qtUzlqqYujTtrgUaEPlzA+M!I~DHA-yoeX>=9v?RCNr%Awlr94_ zKsIG&LS!0VZtAL^vKsw#Z_>t7Gwlj24MHKN8T3{Mjo z&X2oSpbeWSC_dm$$vhHInIz^R=fLkh2LQW^0dU42^>?RdsIy`n9zEfz*L$9?GNDQ}om0|C$V`2Gg zHDTWlZFDwtQ4_{x`uPXQ@!L5NdUX8k=k?qCk4_ROKuz z(sk2ypmLzxXC8?bml>+{4*3Jv!gI@5X*@5FF%3W(7Vsf|$0Z-}hcT7KAU zPq0KF&;B}A1~-LGA3+RwLfP1KjvzhYDfyLX zzD6>D&?qb*H_*a@JeHGmRsJkLKhq18tFck@CS9{(2CdFm%(z@ubSTNy)YOC((u^k{ zGo%Oj57170=x5`KblBwMH@q)z6X#vLM>$hS^jO(XN+-}*n$e6L;64$cw^p*pyd;)G z7BW(VgdfCVLm~z4F+U+*qK9YYZ7M};j0a6o_SAN=u{QA?nopdFb4GYhfW|hG0r*oK z4A2+fKxpW6P7?f>zREQQ@5mpwzG@T7mwIjrQHG+dH$JzQ-hHOWmlnJv4UZ|RJMuK>&CON<^;%rw zMvXhC3eD;%OW*OcG8U&*oQ{%y^Z?K5i%Zf>-d5F^{>M=b(DZoFawD zyCRuIz!gj<%qt4cqv#&LNi&V9O{q4$#52z;G&Ukf&`v0%oYCL(Ms~&h>=|`ouYTF@ zlt$ql-6w4WEBbc3(meuyog?}3zMd0YZZ5c&#pS0%%X|FRKP&xu{=vB3T4_@P`feo+ zgUqTAo-yCiS5wdr%6VAUknvp}#R%jDjkHl;>q%;_%q?)u&rt>a`wy^HCvl-pU(K4V zQ`AkKGhZ=)qnpJgG4F`jBJd8fUDpuXWQxaq0^fL&IH3AYp{aOHSBdTv2O?=-Zf_ZH zcxL{p+_4;**NQiI`Qlt?*us%nQ4y1}YX0h*Sw0y}#d(;1-S>J6;9J+J4xLAqC*`8A zLr#k2h_pz9I*e<%NLwL~mKTbPq@7Uwlgch}R4ziI1%4Fs$YoQ%25-r`5YKP5@&_7~ zChaa6(;&Mk=&^qBr>XquS>apHV!W(3N^OUm3I!VUJJFwVaGj_}WG?G_isL@EmG+X_ zVj*8H6yJQ-x0NU|{_u!&2s|gGdNZ-Uqd&aQm)gM`k>H6zv}D@51oK`Tzn(0>$&B0 z^safU8_u;j?dGrLzj6-b9LPCv$#9@}H|!!1O_$1`9zX2e0(z@=_c`ES_~PdUfcNuR z;44=ym(|bc@YjF+S8@TiHT=)-{7+k4v(RGWo{2!(Y&>_u6D_ItFP?A|J=0`%(xj_H zcTE&9((*T(aG=>t)p(fWp?P^y@%Zp z{rtY4hdq1tHXo!~6oSdrz=1knOm3Ji>vCCWr%lE7(pY>^ZceULzHh#{S}sps^u{=6 zbKG!)&a=_P_?1^)mOG?hY9h^m%cLPIhd`k6^3pJK=BzMGmh`wwSt_@6+P)5hMgOh0 z&h}X$U9{Qxjc@#!H{UDU=`58_ox{KX`@ef*_)A~1H-ve|NO%rN(-|?xbx0C z1-9=MAFF*X)V6I~kHS0VWS6yo&!b- zlF=qmsVp63$xTd;4*o-Qz`!_yDN;<%%xn%IaVxzW@haX@e=I=0tW;xO1Fk*GQMnT4)pY%hg`J#%BOifv$L1RSzZZzQ!8w$I z5&f*E%7nrk&nY(mGA|pnRQa$*ph&1s0S1(mX_CTDd;Z z-L_Iz^0mhzPzrH+UjP5I_a0zY9ap|@b)v~R$8K^GNJ1nbA%u_sfh8f?vLt6)_Sj>4 zG&3H5_kC}^cgNq%{e17-d3RhwO% zX);Kl+Hm^pvv=*PRsUVPs`mP?wMs9Wt=qIU!z&brtjkE7!KyvTOio+}flMeq#wrve zD5j7bL8`R28A{>Kojaxbe)7WG9Ah@tgA1fA^=+m30{3v4)*54-NeF5}ykdcl;)e|p zks)l98}28EQ3#k9A*89wwv?Ku`4{3E$=b|h<~ZXzde;^$n`=JTNcXaZ!Wv zA_o$h$TSreiWa#EK^GJnlto)$93&JY>zSfZpj;^Xg#Kt$j&AYj879o0qJJ{IMu1z0j zrGH+?P8y>GPNu{U8e?@~7t)K-XRCo7}M-}UFXNoQ%koaXUI2MmgUF$t_n*Uu!S_fe9hD} zKVhz8+Zpn=u`6{`?AEYv*Jy-m;9iCLFy~-gPHx%ilq@5e_O$zwgS^lC^&X7$X;43q zz{S_W*8}+tIj&9aEB%NO*Gu1YtIfR#x4c#1heH`)Z}m)6%I<@;iPS+4P9nwWcbV6a zCuOj4x!;qwZff2W&RK%9_+#>tj{2uCB2UV(wytB;-y49CP|3nQwlq4xwOKY_y}EM{ zUr?3SR#Vr6zAc?f$04kJz3MVGqYLf<3Hg)4pe{w`o?TBGyP)B=n|W2{uRvzvgp|hB z^2*j6T9K+Q@@pn zx`#gN)C7W+gQv?Zan6q?yhEk>pllh2V~Oj+p={sTlJV|G$a_41A5fGLz7Ob~fH2%F zi)r`cY-C6ji0uA322j=j}Sq zr8oNEx-?!!-%ol;{a-W1Ebp(t{5^=z406rT_Sk|8O6DwA2j{f%oT+{H5C~ z67wGwQWJ&d)TvWVF}P*xR$Bwel*1Yr6a9N;0cZUyIRKq{5tE!QUAjmi*wwAkx+f@- zCrp^&rcIk>-pdO$v4>=sJY|Xz)N^LfHibBYQJ84Ftu?S%V}*5z5cqe${hh5rb!ut; z2-a+krGy=>Fla-E3~_4}KJxw4S}UwYWuDoZ(6ep{>)1T@+uzz`jJ0G?HWFTn2}N?7 zr1f^D=sasUZ4!acWCwELxIF!K=*7FZxWw{Uy>gW)X4|#x;BJ|4t80q_UxQ?K)qnc* zsczo9`69#TXifHE?pxpbru+AQ|94pqeq`4`WD_DD5A{Wh78`D?E7Y`U6AR~tR~AZJ z!rBvB6nqE|-@SV`Gb})nI!WuW{NM+FDZ_^!Nr`$wir~)fyWjm&BL~)MjhvHGJWrfB zQSuhMC9+uDENl5%*ID6L?@*}sBCXlS#bj?`@+aT=mJtPyJ^H9$^GU~I=zbVNYH*RX@7{?&17++^;-6xEzctJx+F?sUs zW`*5VW8a`bgGH_#ac{o)hPM(I88}R9JmRrS2s;e2_+Gepk*xy?nQkwP%Bx$qZf^Q# zrn|w)W4~UuUwY|9_rBy2-=~civKm{?gRyMP=rKm#&C$Ai7%nl!PrGxP)&jgsL~o6) z7q>tWVP?*J-R_%(Hx!~RwXPmx-*|;&ChRxF-Ah_SlJy^vX=Ew)x|vAifdd9=JiFB}#z5eeS6((FHpo{z zlF_OT95}@42F|Pr_wL+xZ5=e$z(bA}%Ab3PM=s-S8;#i*sPSRm&`-u@cvbsIA;MhP zqwxJJMG$%P(Z@tq?=wPp`t)f=;^GN#;J|((&hJ)!Sbq}{hB`sevUCY8wOnL1SI=HDu)E!`XRh(`%P(2DZQACzaW|UG%nLAz zV=lm2kF*VpFK!$+){PoD+O-rZ%i3hGzWSQY|1jKONs~_UP`>-FyRCfImgPKiGCXN8 z7-Vfxj6LvR-nny^wX1_#!*8(K!QFS?V_tVAT%I`hg?hOd)6tP zKYyNiRQ0FMU6AmKmHbS(ZA{cZTlMcW390W9WbJwtG_V>KNzY z?TV3{d9tg+^g933xfI6pwy-I zduJ(6xXk2{E~KFia)q%Fi5X+VJ!vR?`glD#!gYp0I+5S8_ik%1b?q}FNxi(%=NdYm zPEfZK%HaJ!O(xczKI^@JLAH93iLa*!_LOm}9n+scolwKD&pFl&XUoOp$&6bZs~L6*w%fU+P34IUlo0A~6|i$>S1#={-0wi>XNY?ynG#r-4BXE%U6WD3 znSPvF584PuzHe)dadg1wwap_~I##~3*5eGtgf%6~HS#$IUNdtbT+3aj0jen=o{Z}~+ZdSI=Ca!BREy*~UNJ|;Mjj0UHN&J4p za&kV2pC|w6QA7PmVLv%!`B|=#lXA(~%1p>Wo8mMlL&?eho9x1I_Sx*&uxt2p>UldD z|3m~L0ug~L7=e$K{HE6}$SW|9T@=y~wu`kk=zyH1O8NvJa|L;FY8M)hDkWeVk zQwZl0d35=Z*~-8MDBpc2`~0)LCk%cluy4NkW_c~;+BzGyc94{tC>D7!^Dk%eNYi8i zVwv#l*Ge&3A_Y1!V?BqGd(4z5?sd`8;?K!xLYh`G8WPdB{z;8Yf9Gr zsz+|>7&Y*oUL@g{CIym*@a`K$RR8)nzcEiXLc)_bmaI&`I*XV%E+S&?yYG6XvikaS!gSWgC$FrT38*txKPw$Brs{x?KTMWlFJ8$ zdAMJA2w@fc%U}LVFG)w;GAUjE;eY>wDV29h$%=v%!vPf2knE5FD0)A4|NXY!8|{d7 zd{~=g>$a^nxoaX1LyRg)50}c5tC0~ZR^coB4=n@2VC&W`?#Cj%A-^B_^FMe0ECUf< zF!9dEgYdU9hFI{y0wXe#6C~P|pVD06Kt%B)0vCXQ*N^H2))s-5H)vH8w`t8GH|N#m zE>9=>3~cEdHP^b-dGhdNO>gt~*3+l|m~3TixLXopJqhR2gE?PrN7sxLK2? zBKiiJ=kPCn@e8{WqHV^E8MY(>Bo^Mn4?g&i`q`F7JVGin){NCy^?}IKmqp0-?9tu& z^2Q?PW@`+Au$y?>MDs2t4P)cbVb|Ci*+2d1PwgeDuZXm7DhdU}`de?!a_vQM-miX} zm$VN*Txg_ZZ;dezJn*2~BLeNIr=OM#%^f5mUgAXW_)yVIh`Q2UBr~M;mMvQiAJ%!s zc%e{Z^_?QfufP5}_l&M5EcR`ZYudEw7WTWmyv#g&M~)oj-k$xodrsrXP(=rss4-E4 zu3IXSyQ9YXsgtL;K7IR`VgSOhmm-OLUb1FJnBjipD4b&x8DxFeJ@@=`?lqC#kjzA2 zdH(t5-4>#wh%mkWhLLWg$a9EsLL&C*(??_3B=yft<>58YH7RT=kLPPd{N8QE>YTS{ znK8lFzWNmvQR@~hT&T9=lxCP=$k_M96Hm%`tgRU~umcRZ#tywZ?Q$6t}f{1yeCeaV4>QVEnDh#>zN^J`)#+~s<~#ldE9sC&{6mL7B^pW<>#M! zPPlb+cTT<2+QGcJ@5;@tk;=}|$8QkYrufpcfak?EntwBw*rI!Z7dX#Bk?yyJqgS1& zH|?4B*+O%T`#*obdrSrtw112@!0hV}KP((n20*i!2FCB!{p4gSfs)oqRF^L9MFb)O z5rH!zkmx*e7&H^V&v>m8pzuAH?c7qInzO$i;1oag1|bs73#doFFs$<(-aF88orshM@~zmktfz2sScQanpC zS>!B!kb%C_d7n*&XOkvTdXn_c_B@d^X1?1 zbqVWdX*izl^r;u<5)Ni5GF#esEFusQhzMMX2z;#MHyw9dDRPHN0nDJhLQ2ok@*eu) z7r$g7wg3J9`>8y22-oT-t|%BGQ!^$U>e(--pVpwZe%*RoACpjySc&4r!&)d4q%6id zjsYn>5NjVVa6-uv?i*z@|!N`a{WFjPXFZF-!@ORWeR0} zSf0UL#{f@V#*e?nWX9WR(c;CXOt$quQFiJ>2<(@KH*dW50oE^|UVbfVl{Mu`Wo5w$)-uLg{$J?siuMtuZx0SM+2m*NW?bB!6xSL$n zLp4^<4Z@~eif-Bqp+K*iO@KjcZIfdCpG0~?!u;8vJz|*RHSoLN|K7alD`e4$9teDC zzrGcx4qP>0#EL`&&J6+aN7k3p1*z-MMnBzHYfe|Ym5aB_yHRW8)(&$+uJ7Tha@2q1 zV-?NXwOTWY2ygwi!uaO*={Lp~NZA_{NrV0$&u98YjJ7t)1GPC)Lvm@vVN zgdqP2!%b-9BS(+8heUw0bOs)$cq47m_y#G6anibVYg{LV-tHt)57LW%^?<@#GbX$v z!V4uA-nO?)xW$M{`f&`xR;^ksL#h`~Y`f>9RXpy||5!(qjYalwZlF0k% z7*sJnte*F++LoP@N+D2{nRenFuOv6|aDj4UsLaRK8jUgWpkI#FKCBi(Av6`Cu} z;K2h`{t^*}bL{1xWkpmSci%lT+)^2l6%^FE85-X|l8kfa%(n5CC@O?>C;AH{Ju>2n z%-m(?j$Ib*gQzMiSF98!%j~`|WUS2-c~0(*D*f85RV8wZAAFK_uekeT{_y5FYk$HWl5O)e0c~fO#bIS`#JYV zE$`wK-uv?pJm6k?^%cXFdBz6a_tvf3$g6mWd8=>Uyv01%F<@J}Zk?5ZB82*3|tPL;+Ru#xD6Yd*t6HSUthOIMhZORJYUQc_vk!r z`|IEMhUOoCrpQR$-9P=~KdK)&dgg91BSpH?t1nvo9TA8KLlA@($_zJKG)RG<9vQ!v~q>kIRSP)!hX!xTr{jMpdLvXlKU5s(^fj&Vi=9M!|{^z;cnrJ4GtzC>%7B45w4ZcvV_xO z5{L4Z^mk>ETdEYu*SDckX%l6V|TQ?+O1o*#eML`Mz?P9epgYhKDVa1`baKId41zW ze#+*hJmqlW0K^rkI>=~?P|p}2K?KuJvTacRS|H-AS_Uy4-{DBEWCADX^nYjV^GB!!t}ckbA&cLn)0TF zs6KwILL^#y5q?MHef=4c=Ii7kKFPv)V&GLIPtu`7hlzk~sx-$H;bX9cc;32oyT+Ge z!a7&P?P?pGFy>+X>l4RMXl&7VqkfIC!uowi2gzVWoV=d9$fNeAaW}dys@qLB-Q;6V}Sixw_&E9FtVZp~Wrh_z@gDi4Btr3lqhyn$u(byQj+txA=Y^*xex}l0XuzKZkk^PO0T;|^OEiST*}{!8zr(wkwp*!n>yI5hW=03#$lOH@OXFxO3t9e?pZtp%9?~9}mq7G> z?Q35(W5vCDOZ@oCL&t|N<>`N@m1~#Ze3+ZirpAsPV{^cjT2=;QM%oz965jQlWsrga zMqlAgd8{iADL#1cAS2B2erMLi+_6Mucho%?GIWSVXBaeakcXDnP{!C^( z%zZZ~96Zb5;JNN`ZB`cHu?GyQ)p+3zvI^wuR z1R??vfrvmv;M0si7!yCu7{t0q1R??vfr!AT9)XXS{MKMh2uc)YysDxYCIse&4V%o9 zs#e5-spaauzy=j#>h<=_H!*8M)W!bA808?OG+xUnU{Mg3Nx5AqG8;uHN@Ym$pxngc zs;0Wub(hkzsY1%)S%zm1YdoT`LL^+V-ew`7~=OV(%ljDTFTq)%@W#Xa7 zHH0KDSNVi8ML`OIj1rTuvYt6c;b29GKxkqfUOT1e#4G-DpSxdcpH4Bu0f0e~I&c2_ z?p=i_zxn3zZiGUyZr!oNywoiZ<&$0m1SPKya@^!im65635Dui1g0-MgBg>z1Q~~qI zBm66CcM{^=dn(C`Ug1jd7~Cx-x6j}1s$Ir)$ViBH@XeEgyHbj16>Wq8-+0%vwrne{ z>$*#xU^P<8_UPWzyxAcYOo^;KxQB!&#UP;nfB_aoV1m35S=02Y+;pQbKv<_|hA_i~ zl7|dGDuq4>C)Ga5{i_m-SgDA>St5YJ4IK<${<&Z*pl_8IwvHb^TH)5L+~>-UzwZW% zkR3j*$o1^iMIPWHoAL)V{J)@P`_n=!U%B=@m;dB+%0^6om)0{Xqtv2luVg1(mZ zo5^&2Rag}MwzeYD9nuZb-QC?CLx{9P_s|MRcZqa^bPhR4cSuT03`oOJ(%-nx-rqUT zdH&~eF1TUVtlwJidV^F`8>5jL;e34H6;XoTUErYIFyGbPHCbIMqo<4S9 zCyTD{)jbOBC|~hqTtFKOenarVT!nL_l9X6PRDjHHn*|nRq5}nm%QRD2%EWwf#vKMP zON{qxyuExn2sU~n#OPaiy*V2r*z~_@gRg*eY{*#Tnjzh_`r!$0-(wm147 z9i&Q+aFRnpaPYD05g=;tDE2lew@+x~Ap(SYoNA9OMzucMp|=71z0jyt)JA=rFXL34 zDRxb>-XqyWc#yV^;hrE09>%b#me+kG^ppYt zt-Z@PiRZ&Y07**WyUP=+FFHutfr+8P#E7{3TRCvCVQJgRgy06B8a!}`9=*dVAn7pk zo|7ROAV*E>nuL>|(0HTn|HPqFYTQuoE>t5y)0W4uzmKh~ambvC9f)*)ITFAKo=%yQ z%vDQS1&gI1Zw0~s^6x_a@8M4B-yZ`Ga9WRc1kv85MpeZ`x_h{cPy#aQGG$~bQ^A?x zzGC}nbANc}3%}2+aviE|k=SId+dryu1y5b`fARUCSGSy+SKZBCQpWtGCM{K3@o*U@ zLja{2l?=||OiDg4UugoREVPjCLoQ1=qpLRT!%n|&7j^0AEhdYE^~lMjwms~IOSB!Q z!tiVgnX$t#$t0JyLv_f)8F}XN|L9LXY?Ia2!7qYqC<#Os0n#*!K3_BVH;Q*v zMy*hxz)XVcFfAK(&EDX`xfVPhOwI%qJ- z-ypHyf35=dTEhiD|1tsFJO&B6+8YWUwXfGGx&gh8{NgXUXVd~Ma)$w()ccV}8lQ#| zB~r?qrdr%V$u3@%63fsQM<%xthUir70-g_9kq>Y6nst^uDr1%w)BR$dHpUDYoeq96 zTPP@1(3K=ae76#J9`0FY87aUZ5k;2|lGfWU0I;@+vIewOGghrqi)S&3c_Nc=Q0SFg zW5oUzB=%STrWY(@h#h6dzRh{(Y;EAO%rY-d;hnG_*iX+i#ILDwk*v{*fA8YWy zh7;`W=g{!Ew~~WMO4BAIQHp|Bp*XuL_hlQg=)~zXF5xKm4_LP~C9YN&9}^>9I2CbC z$H~1gtVoVMxNQEV>U&GU(@#4tO!FOeOhO}UlOw!x@CE9eNwY(>C$06`OWqS1Bn)Jj zO|jf>HzgmLnv0itQU*IxriZ!!fD;7dy?z=rhh~@L9nwD;imC8{0(& zHyo)5c=Q4*nlF^tD6Zb46Hr~Srl|`mke2O>e_WzzQ?F_C92!09> z)eLF^>@J9fHu1(9{_C~r?}uaFXUHl!6A2i%u62i@B6)={&3egf)twHb>w-yLJ}3z-KO*}BF2U89LU z?%?<1?_mc0Uh_rM4Gg)%kL~AT;iaQKL>A8MH0jm^|48`VIl+IaE_}&;X&4Xz`|UC! z*a-lj-chK~CS0Zu&)(VOOdoZ7=Mv8iuiK;A5imu z^-wv)8WBVe*4qhm9!jPvMs=g1T{P7wJCZ}|MJJv0{gP#YB;2t6N%f@eP8|OP0cMpe zp2MhD&!0{?g)S^oLpxKqOZrvonW2~I6vvAny zHVI4al+j;2+v6@sy;?*Wv{Ox@=Y z8R3{2!c!)>7r~L3y#T*jk9d|izOEzazVF9QYIe2q_)z?P)apr*l($rjEq*d$AE3EO4XYoUK!8oQcQKq@M>T1NGh8EqGKepBdeW-_ z<6}6P)HGUWvLOlN{DYknT5x0GVO?YMF0!k}xa;I{+XF`5JJG#*_2S45+>e!HAJ6Qq zD@r7x&wlgOf)H(N#+Fj4_1xDr0aI?^-RU5(e<(_~jlX=5pifQ*v`r%#_QSwhd(0r( zorYG_FmT)LYRHDx6jgQnYnT6ZdWSe!d~0%?&B?nFZuurHW3=jAz!>R&Fu{^wU6x0;dxc;*%CWZnSdb-wOcwEs8qhOQ`kr`=PN~@ei zmy6cubSeZ{@UCyKX?kY7LcU(XBNE8_AucTuiA)zm;?q1OxyF~JSg#@E5#n#VT3OCa zvDVF6EUFs&0_!HtWpEpBjZv&?XkAF*Ft*#O;G87ECDoKTwd-~PV3KZ=fxEWD&cq*) zPab$k;d%28l_1i6XHz7Y-HEsXAgttF zNZ?w#(&SLI!N#l0OmZ{U>ee`6N%_3JOaz>dn!5amJrsqg~&I5wAhg z7XhLj0elb&r_aIZ-tyBD#dLRf^E~$a`oeI2$Stce!2v`qolRa|zNXo=_i%kVhUc~J z*??B{_W1&O(X5MMRjsHPVo$OovfXH_e6oJA6y_zQiLY@qq7?icY+FfXYS;DRZP;@ zkuScdIF9YI>#XZ%eabyct}0P6A-Jik?({wu(N&P8&Y$br%k5CdjYJ@o=ie+h9@6`u z;DGGj1hI*_hjIopB$U0nUUyMZ-%*W>%zjwy0w#3kZq&I};XM9Ey@uP~n+M$z>ITT# zbDA{$j6B{dq}8Pi{ux|b{aa8+$%`~_4tzz`z!>PZVVF6ka`>ypZkrVuTX)lkLcCWmyZ}{EX z-PK#w+2l0;KJRdx?AF zq*i1K1v}pWs%Z!bdO61M1NBe_LUp(2#*o~{PjW&z-4{po&WD&mKVM^+Ygo#s@_qnLLcPX7_nQ^?Y?jL z1JM$(MPe;`c&8+`OCzhgpD%6z6x{E=9|m4$FYSh-l#YYBP+E7t0;?p(tH1DC+S>uu zSY2d#c_RwV<@zhi6WsG`&cH=Tm13q3aIb)Q)5i`>9#VUpuG&sTB}IQ9AAN@Tl= zI|H9P#Q?~u-WDT4BwX=2O&=vb6Us?Wkxqo%TLvcWstM%Hc!6#|Ab)G0aBH?wV7YUe zPze4W;nW(7eiQlAqKt{hKkOq3#m`J~^y+x9pPP35ax7yuf5v~j0Mb#l$oO4AP&;-t z=z>!amfaw&NUYex5Xo<^iY@cME4~{}U0H&i7S;Ng0xQdsqTh{W=lA@mr^!WJ3R+-SN_x2FoMVd6){)iPP72My zQ+e4d48!D(XY?^5N;^vl^AY2Kr31AI;*&DCDHm42F1)X|T&w$xOjlRB&IifT-@N87 zX19Egx-p3^5v@MjuR48*kn}tkoFAb`us+B1dC9lJ&I|^BkC(Vpzjw|dhcn2DQKcR* zMJGfxEfr30Gj(Z)=}>~U9KyD;M97Q_@UsIv(^uwnFGT%XK_(rH5A`Z!e~)n z(d`XyDE15hvseFIlr}Ny#be8zL8pgt@Skh}F#}z3x5vYPS`6-D6l&UDk8e;CKiZ8n zs!_N5mOR&v77DnGHq?3cAkcaCD_*#=y~nsSWTtlGS5`Jhjz(QO;ar~I-mPTO>ddm(q7)x~YtUaaEW zR{;qE24-8YK_^HR%dv5R_IAUrMz?h>Lie#&RcR8ZT{mnLRLYA_e!XjWAWz`{tJea4O^10OXRYsNywS!8n$^Cavwg<8Pf4@1)Og&yzQ>8=eT8~ zO&k@gXv3oyU5{#d6^rO&4+%{QlsaBJz!L#uRE;yf2~OFYGY zLjhvS0&z@Xc(h~kob7;0F&mdmwbHh3i!hTVy`WEy>6T0$043Lz?`hAgno!j_)MZ@2 zH@n8is$kDJjxI+s8&EXmc(ZAEtP~4tX2NvDg0j0p8)sI3eSYNkOx#~feNum(?oS2j zxYIFve2M!UV-1Nzxs*yJsh#|+ByU9n3!mbHX}P$1?SUt&Z3`AZh$?vNd59&Aoj-AB zN~A)<8n~WVI9S}}@1{?W35Db9srO8jb}f?=hM77WyD9^indOulgVY`qi<{V)JC0eg zC+qVbCOTi~P*^dn&!#M{KxS4HhSsJPz9!Zb@SXeqA7Jf!+~EEys=)$jz^1zCXj3d69F8iR zWj$@Fbp@nRan5w+`-7$}R4m818Tb)s&S@P%WHKs6L;>bi+5uRLF?an@_)bpxseck7 zOnz{Ri}k`86m6R%((?jOrZ0V&Nt7vCn)%Sb84C$Yf4fscP&rIWkU`@~v6PHdQtFf} zSk0!@Hte{^q(t?t@3yJ%h5R?HWsOf`vTQ`(MV}_;VcQ>iv#bx6MkH*VeImdSt%Mv^#%S;W>{C639@7LV~Kdid?L^?loDUB;)iT_NV~&H^sHZvN&8_4v9Ngy^?g8p$8Esxc^Q4VcQX-3`l*AWRPpd zYSfcibVo7h>#Edav(Fq0q_%aUFy3Wq_o3+;%DjM3B;_{G(6ncACcP<;72d%vC8xta zz~NG0v*u$&W`((i z>_bt|vbQor*lfCMj<+q@Ila>4S6Xi0+%m!nIm8m)X#~Bbdhz1b9U2$S1LtwbHCoGl zx|_@;Zucz` zw405StaxoK2lW#XhxN_ee<-^548RKFkXe{$BfZi_%jk zbSRh`3qKdvAR_)=Tm}Pce=}RH{oR_6EJqUcd3rzM1fTUFuknzKoN=gM;$Rqay|D%1 z9TLq;Hhowd^*WvzSOEWRNCrPx@rE@>Xg?AqSsRS} zstUzOC&7=D`CNbzNHusu91g#Jvf79>8Yfx4sW>wIOH=ZhZFRHFpX+D^|8=FaSO6R4 z74xhBjqzzsr-yjrs|`KTFlI024ZZhQjmLaF>x1x%swjAdZEuNcoH%PwfpX<$S9Otf~8RbE%cL;2^h@`_p6dDSgKU(DQ^43P`F92g%tBbB+U z_7M%-a9x>MiJK;=Bng~o{&arO)8X**%<_!^rVF`}k@-VHaij~!#eqIlE2DzBJ|%NG z#;Xv+TN6|BI4zD+wt}ccZFu#Q$XbT+bEjc|dyVr&^t9e%dGSe{n{)-eGzn>q6e_8b zC&7p#lWA}ID)vw>*b=>bvk%qs{nd|}k+eS(`_!zIic_pRcX0C+!h=R|O(p*+eP<4e zY@Wfwa-2*Bu*CQ&H3CmKRTlCuXqpzmF6MZ8!5JF6Xr2IW37x!j$ZpZM@zH>SEMbJhp~ zygUt5>7ovu-M#9NX8nsvChg+k6`9jV>uc){iiS?%nD>-3Wbf0? zE0#BD&~M8zNp!;R9x8O2MOpeFb<)ITB^o1B++rOm05h}Bmw;Vi%}B80{ES)I)zJOb z@!?;Rd~WcG@CBq)!r`OiV!Y9tRTECy-qM{(uHG|;N@&hxSBVZp_z#MpwT_|Sb(i!S zs{A#|9};G#61Vley*LG(Urd_MqG?J~6x05&d8$4XT1P_IIu^i;YHT$3fyG)8DqN^vFIJvpw8@p~Mp((fNY(wzpBf!xDY3 zdaXE@f7G%lF4u(Au9FQVRplFG*orLIP$%>I9oiI7X{>^p*M=dE8lkip6`CjjlJpGE zQN@EjMLq*F1||REWDL?FHdH1oRYIRlh%skf#oJ zLd%z1oVJlztU>n#ZkWoe8pXV01vu5=lmj>PUWF-~RO^B?U(bKpDsvT@#ddBY;jTM5 zNnUbZ(j@N7Z8C9i7|hk-kzL%w(|7g-oR@c~yHfzUu+OoS3`OjPhSN7r+I;B<;o5eX zZU=hQc!2kNTN`o=5Vepr5Y0=mE`t&o11_* zL=0v!q{RFe_WREn_^n6Bu0;gwavwe|b-S=lh~7h6_Jd z2aMw6XTi(}12O3H@3QB<$akBAOHg{}KJJiUl_-R??_~IEA~1BA>RK%l@vx`pEJ$WR zwM1?mym?R?XX(X;bR!M3J_eg1Eq#7f*6{Ss^2Ay$}Wo#{J&3eV6D^F=`BU#Mi(mPNTDe9WC_4y}C6jSGm$A z$D=tXNY~;cM96>7m=nLc0LTl42)WztZpFBiKa4jKZ7-Ho{~$SV`#eij6vUnImnF1C zEft2+S+$YNKX#Rrbf&{Ti<4gbp$3vyx6Nizr#ANC-MH6U^J2R>tk>2d3cjnhZWX>? ztk-1(8(0gOPZisNYBzb#Y*AmQ-%hJ8GWWh03j3(x=2kDi-2l~)BgMxpbn0lS`OzXn z*Lpia99Hn>EqnL04*kXNA4QJBuLsM78|}!>O}k(08nXd^NPhDaF=-YLmutSBPHZm_{i+RlAztZ8LS*(m z!OtTfeRw}rwNWZ5X*b}IhBc;} zDB&8OY@J2trOrzY;i8^(6^C!PzLdyDO3kROZ>Q%eIbNfN2mP7e)ZN(=|H_T!?)U5a z$2Yi`obF^630Coef@~n4`5pkLyc>^)eAQM@6 zI-litrkn4tPdzFLjjPoxmzT~a-;R?0Sh)Ue0^=lPUN;4KCL{X-K-KtLIm1M3i=Se1 zb^`@ zj~lE%8;RE!!A>3AWijQ<^ZazQm}lN&lJ^Y-WSwq#cW?()O8O;UisHhG;)QBCpe;l! zo$Tj;CA`e)`6$*qf&^g)ZIM2cu1jq-3T02SG^ZE@lxqG_J9r!)UYg9|kXATAf7UkC z8}*21D-ruxH3W<^bI?WXp0rzU(c2se9eJGFuRKu=nfvHHKhI&nMC*EvE2P_X@v`^;rInaa4Q?0b;zMLw?NUE0Zu zXYniH^Vp~a)*PYT9=|INcfZTi%HT!2HBnv0u%Q;I{#Oy}o8@1a4jlPk8aq?{ppm}V zmR%EEnz~f6!))2!3KB#jW5dH$Jyc5oqtKBl-$E?)>*1~wrL_SZsr6UWg6HFW%wLN* zK&zrIhz;u&p`!Q~)-N&hluO%9@1?(1@wb`E^t;37l7x`;sLmhF>9&b4TjU4OhWL=q zCj0N^!|ry)({A31Ws^|BY^v6(K)iH40A@WAdI9!44|X~FZ3gFp*;y;w93z}rG4`rG z%!*FSJ|uKm4K$_g8Z_m2B2bi)4VhIM@h$atu;bd63A>X6(04no2GNUTaitH~QPspI z9-ky=zAEZ{G>u287?4oQH+P(`6ue`3eDW%K+V=DB(JZc$#PcxQ)5Y4n5xW7VTKrxH zi_J~ko*lU$D6$5os=ns%AKrfkB_)#nR!-KkZ71KsYhI6SumnjIkFNEDNQ!|dof{1K zb+!!+W@^&afnH#2h(6qyxRSgaEAZ@cw3TUFQKuE@W@34jTJ;Cx=-H}=1J^x6C?MWyWUOjds6x;BG8nSn@`G_x*1 zxy47MYXDp#;oH|iSOwo$CE{GFBUA81l;`s79PGR@Ed%Rc7)E7A+CIS$+{VGDA}>?+ zJGqFoi`(CC<e2R=-vF_Rro=-o_a=o%zdjY3!UM@! z*l=EH$pIE$we_vi4$BzFWU#rZXYsiW$?NPf2l^h!JS{<(@u$2{JW+rLQtMAS#^&pH z6G*s}@%oim51$_xvu`KOIs%Np>3ZomS7T3_Ky3+1tw_A84fh;*2CV*hf;k(J|COA) zK{DS0KG~_PzAiFnepR@W@IoE0e&<&6BB+07HsHo;jSe9L^`%#@4tCi{kJh)-ESmO1 zlrzVEuqKsX$QVL(adYHo1|ihXQr`D zuDCwT^=Xbb^S0k2j}p-yKVXM}3>^8Lk>cf5{XA_Lw|gNGtD*hbU>v$Qw`t%vZOVCN z{K57&wC%;ka@yasT618fyMo2;tknY(eydO@tmd=zAW*EHTQMZ|E#mEmYC?!S(8e%I zZYs@z$b^ikHBoJ`C3@*a`e<$RB8YxR?U2lh7aCp|?ndg(?!VOS+v;M-dmp1z+g)zT1iTe(Ss!}N4M!k9{8CI2DU&Y z!C$gHGNHiV@4ceIy|pGsM_>rA?55&a0OxFhZQhqKOuqHjPpp;RGFpxM7thiV9pT`K zSe4pwk@dmX?R0&i>@+#Uqsx5ZgW59Jb)CYE1}Fe7p`C+^j;@^HyxCp-wK7erMTN}) z3;$z&x)cɵ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­gw&x8fR2k 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 WMM~Xr)teOzK;Y@>=d#Wzp$Pztx09a$ literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/prowler-cloud-credentials-next.png b/docs/tutorials/aws/img/prowler-cloud-credentials-next.png new file mode 100644 index 0000000000000000000000000000000000000000..0f73b009058bf9dac3706385a962dd5ef5c06424 GIT binary patch literal 143966 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

No0PZ;(;KG8?8oI%$hf`6pYAf7D}AF@W;!lm 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%0AM`zoe;E|w3jPQi2~3* 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 K4=V0G4E;Y-?hMla literal 0 HcmV?d00001 diff --git a/docs/tutorials/aws/img/prowler-scan-pre-info.png b/docs/tutorials/aws/img/prowler-scan-pre-info.png new file mode 100644 index 0000000000000000000000000000000000000000..950a45f3c154824680015d870e739ea950aeb83d GIT binary patch literal 426215 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 !`u8&KEMLZ@#HcB1)U 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

!f_9qZ?Jyu_x~eo4Gzk1} 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�&IjW+plu%P8=4WRShdcH3++4z`}M0LrWe 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�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%0A^F;cdGWE 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

bL<#S`4#zhe^msvZ{U4AlFe zF8c@12M?p28o7l@r-|==CvDnfynvY-LflBG5>s=zcJ%g%=kd0G#W1q=COWfx zcegXYw6vwrf>~!)Hk_JKSZ@POzh5O5@hWMd*N|=vY=LPRhN$V$!+&dZGqceM0Qz_< zVNl`HmwLSQhO~9x$A7TS*e+-}sFv^-*W`4yDsxLnfb#9(GD2vBs_HAlHfu)}DJoFN zgJ5*ZN^;1;Z;SCN z@pDyY_@k>$Yn^94*G@Fy3hwtm)!x$@zU}g9vG=Qoolb5jT@VxIp7vb(nGby?Bk3Z4 zQ4=ZwzFNIxf4$6h^OpLQuUk0iX7cY1*7kS*5CxK0$2VzL#ej)f%mbcxtumNzgO)40*2uJdxJRmr+zVjZz;{1 zoqlQK!jBBuf|V0M{GrO2RvF)Ds_OF_TG-4Uu|A@~d_3CLxAjl$x=lk;)awss;8KH!JH)kY{?Knlpud$sKkiwpip6`e+DsjArR|TgmRZ#aYA?wx z@jZmuv%=W;`ff%rO6%|4IKJzG)suE?ubD3Dv0CW^wTMHT_8-k9zl?B2p0!X_Af2}N zXRe{%m2{Idgrd^d4#kb!N5bE@EIYf3c~;9Uyosl^+fC#C9e%>`1Ce@~`k$#4ZdO`* z3J~UnM+gBD0*{nx4or1^9N_znIS_$m)EYp#4EW=2tiTyC8-N7a=b~zm$uEO@wF4A*#z@0zZAGei0t9 z0NIW1(Nd$}sdzPoyqZ-?OUOm=cBUb0s;M9X4D$|eDyB?y60ib$NpqKo$Jt6V?^6o> z3Mup%=8M0#S0s&RMA?g=l(7Fg!Mch4`~xR(nGL&)c7a zyw@E{?X1UI6K}1w1>3d={V!TU_$ROXSx}A0Uuc zLk|rpXJPs=K8@U>xkYKxz??m6P}=sDUV}C^xH(mFYLC zhPUgeMl>^yI^a=Y{<=_&B@@>eYjn`%WHd8S=r7=lV8t-7VEc_ks(O83>8u(il2tJE z79x{9G6NF!@0x!4W6Mn8*<1zI3ne}bf}t)^EXgV<6WLF#ft9iwR4r`S)tOBig^vK} z-d-m)vx~snx%heMDP{Xn;oB!JtG+Kzwp#1DJI**X3oNdP%ri(VF_=uml>S(D^}$KB zc&Y4h)>LHbZ85v5;IwVx$pDBj_KWM}mUrq^JMie{t10$i+UTW>u9gX*QlIt|}*g~mIxrtoHT)YsRe z)_X@h$+}Z5F?K02sS)gK;Jf)_vN6o_lgL|))sS0gq?>P-VEOn=VRN+gyAWx^DLACj z%||aawUbsVkW=PTm8GE}gIn%~$m1EzEt!xPE?{*xt(U+^xSM~A(E85i;U>*?UJXrx z?2z5?Wxd`}2;&s~kj^Pxx&O%Hje#!R(_$a zYM1>MYmU1jz=5pCcS+~139wj!5fh)y&HcExJ{k}3MC?wBEzzl%qB=D2eYB&CZ=yLo zZdNvsCh3;|x$2kJH5J_ex^SQ1eOfhAMzV`J2kP(+B9*maMfReKBvjUQWHazTBTr)g zHBmU6V1sd$sSDH}RpUlE1g*h|Q=eiAuF+{@4OK0I0Iu`sDU>z*z0+S5Qb2){X#k37 zLRosiH#~qT|J>it*>ms^AtI7GX`z6fyNTcqkjL+cTV5PDQkpt-zYlAx2zw}SOL49@ z`DvZ*9e$j^4y^M&SzpVYu=@0WOZ2>>;kYKhyfeck7UIn(l%X#O1$jP zNJPz*Qa3=$#7~3C9p6y%yuGCC`Kv^#qXaT7RHi_*|IFIuVosOrMO`Z*8#rDMRnGWXPH>Li=r+l?{?O&Q z-N-rw*xGGymvrF36>M^WMuiTHt&isX{+{HryFlmzsUc^4q8|pkgNRp6cWiZRZMFI% zW!eYh)R>;B-zy;K@F@H%?2r&qM1+2P-k!3Jg+(TNUcq7NL>mi$5b!o2_SWbG-x)Llj7l{F z&=|vgpUYnjUm>=CElPBo`1B~t91RUg02L%(*t43@-c!7jl0H+Ec~z7jQ0~f7Y92nfAKUReaACGisst~r3Rs(_>82%f-(U4! zuUG#THM@$hXJ3db-2E^%$U)+j>cDzURP)y%i(VzuOo=-=OC$c#)JOVSFj=SsdXAhH zjNIm0+67j6&?XxnykAIzua26Hn4(UZg85736U$aMs1Se@1N8YsAXO&e-nmaQlc)6p76gxNZsG2IccyzitFEW2=lkreVXGR3 zRMFn<-TbfvJzevZ`LcbPOXVC|TkLr)E2K4H>j|3F!&$X*VCrnnUakEL38K(MZ5C0_ zh{)0)4&^oQ<}^qf-@`OYMD+OazMHjK6eDK>69NfZ4`5B2zKac9vT{=of zEs`FkiwB{6$Qb(anqF5@^K3@5>qibz%(eirW1yO`=;Jw#U=Ho{Un^{8i(8%QrnoNQ zsdUp?-S21q%!N(P0*E$ASwXP>jbOWMz?OKj64SF9Z;XKik#EP(L|J4h_s(jk?&|Mw zj|6=!A7g@@3AXa!Id8sE_bKE&aHvtl5xlqkQ=EIA%5S`q0YQn-w_4T&_~Xyvi7fLn zXjA7-y>*%=j{`DQ>Vfde%E}sndS6~aJ5I=RN(sOs)}EWf?fI=QAonbozo*M-C?a5n zqBTXoB6wAO1D$0qcrVZrFJ!`Ppx_}Gv#52mUimOKbz;z2B{a~(%(ea{^k8|u`j*BP%ex0S*k_r zxTU1K`-Rto@j>i5R@c5MOCLO2!x z&sl8ieUGDb{_)&TNq?1lxSH{GV?KC2Oghnek?FfT`+UF2Cw{^g(emkUd9!=3*>_&P z6TE7esMQ6#)=CO^kNzpq{_BX0G5tM3j8!ESQUi4B`4a>y91IIj@k&ybz?VgZcr%=|uTDQ<{>JRQCT*+HusO0q zm{-}0p4Wy4ccjnF3~T6?YrjY39;`gK|KSG2p#X3zmTKC3H!cBNI@A;ObZyOv@!qI* z9K5ugxHomUd~*b#i^>G*K76a}Hcm!}-}`0RQa;D8la~efc9AG-gN8#vDjT1ztRLHH zFNW%;$Y9g7<*_<44MJ3}7^Ct~+R@#g`$cmnjTixVMo`DSvllM?VDCj^lTVMfqRFQ! z^)v#D%{rTl(}9E!mkJsp7fc1RTnBS9n@z76G}A8k!plwNsZKU5WCXz_R@g!~+U^tf zJT4!i^`yZfcAr+$KXt0aFpcWoL~ovjZ;ESO{N`@n{Bl4f8TaEE!r0Nu)scJHPYB(l z4B!W@&1S4n>NQalOA=SkM3~7EIJGU44HFuaj+S9D7B$!8AO@yPsm>r>IWhY9O9t8Z zmkH`5DkB_k4Uw3hrYfjQ{)Wb$p-Kd=&6l<vYK$#%L2|u_$oqQMdl2Rxpb8+_kDPsOdFaO+^ZLRL09G;d>!fM zaR$Ar=BtQUm>v?UC_UHeNY76puVM-}TmVGTMK?3XR%%`)ZT$J<=Nn$8xd5C}OR_;j z^Onl<4$v7%E9XRM-_!%_G!_!-uJDfnrO$NC=S+X9ExmF1bcZO5QGXJbx3%ZM>yE_>K zedZ?Bm>0o6H4{ij65)Sr@La>HS6Pc0hCTfL)dS{?VJ|5G#)9#WxHAmnCgk=;>J9;O zX5-C|OvCY7Y(l)N)||^UbOG@!eT{;$L0TSn4HUTJ0VoTuY11wT1wL!UZp0%?z_(B1 zo$@?B{XLZQbXSzfulcD%Zh8|{n~Y*_lUwvxUzh$2R=ayt&S&#MwSz^=fc1v83Jf0Q zyib0=BEOMobK)nc{g4%VzLM;FiS|c;cfk?614_VjB$P`{8wc6kG%DGwo<$hK^RF_B z_oXBKMrZof%@NmaxpV=Pr5=245S0oH=E~&t+8cGK{1?pr7u2p^`v+?GawLk9;2~Ds z5ma69bEFRY(`-zL)wTxZzndtAU-%-%57h`7v?(3F%pX454-2}33H4Z#8Eg>ibZXf6 z%2x86fx-b7)hGWTooG}vLY@ti$X7j|`eAWilAV`+{m``KOF%Z&o(7`6WvF#wq}&iu zJy?nU@XoWCk;)C5l(Hgr&rXAIpj(x*#AedLJNgi~_Pl^1G?Gtg%~cEW!9SaeeU|Kup8Uut zFxMy>d9{Sj8EV~Ud^3DK<9#17-k+UE*Z0cH=BV^?U(U_$e z;9jpzMA}NI<&74nKSXGP$0Fz_u(|zM`*Wid^HDJv=BL^=@D&=245|4_qmX`wNfLSu zGoKhjL|8!8qXV=%V+Hm-U#hK^L(*oa4T}HjPJQ5Uk-JFvnx)8`a9#HNXz?u#?QXrI zEsQ?yY;?1cbvRL<8Xfu}u6DD{;oiXyT-teIOz7&%xT~enV1{hMQrOY;5#Lx0-S}ta zoKW#+>5Q^fIv**XpZP1_rW?UUT6{NjL#2kFUE6J1Y1EKEO*H3T-@g-!zKTwlefMW! zV#=cpd&#O%R}K{s<$pqm86DT}$$ix9{V0|_MfikpDKDcY%F<_i*V>PPY;!F2st-G9 zujrwkX$?lz+T=8I6O1`>SV`tCmZDcTiCVIsv&^vY=rH%9NsWdnOA3y?$iYVZL_uB; z6(vq6LNzdNi!xCT>7KMpsF;yKT$-_rp7NO1U(H1=$XOEtGSG%Xw5ySh1~VxVL4DwZ zFjD*2Y>|FKjxeXd04GKpyZpAEq+3C3S}D!HalN3_KpX9^&QyYdvilZwg>0}jtZBe> zrR}?7)TYX8jDPFeQ&ZDoanwnaoov0XRq^c9 ziemaun%bHxuC>n|S9%p3iLyK$t;$jZ=Vb3BmbSONQKJBv$ovGre{DX29=O((?`{0U z85#{Af7}P~G5w8R4quW9E;dzN(QmD6#WOW!%*kock8I9}v+27S=}w3p(=JA#;Nfiz`|>WvRL(W*X6(?ak2F}%kgAi@vY2x2Yp(r#VlwA5qMn+6i24>AoEQ&INups?jBNp9^pY~^2;chZ9cC*kmA1ocyBC1*g~1J*j& znj^{HZWKUg!^Hi4Bfw#f+=M@UFciW%7aKcCnDqFW82WtM{^F{Qu>xnbJvvD?CXUE4 zq}5OPPWgjD7j0ZN6~XCFm`ruNxw)<&DAngrt%n7N%`gG5>TrD{D73bLL zoZOMcX!_uz%Untagi?zRRP*k3!*V&A;0w8Z^;jfW*W|~h3v2pXlh#Mx`o0wxSLOoG znq8+Y&SKTsTBG)|EL>2`oB?I7(Xn->a{W75@4{UQLD$5%Lx)5-^%^iK^a6(ob;)wu zQ-I&;j|6w~t)!NaxS_L!Bc2S#(1*=aBfaf=0<1$H5{W1+4dkfEdv4Drn>o5heD{@6 zW80&uOv;PzJ`LMR3$^f##KcE~-!|CUr_&-mW2>4Ro8eQuSPHb@138A}Z{2k@4Tu?* zY8f5lgP-q1Z{ZKsgMv@ryVF#-9=Veak2&C?|0ldoNN54~j#=w$ZLS-B4q07$%>%xP z%6@7gxO+k2R1{*O8X`sc1Mg~KhAEfmjZ>{tF%mc6U;tT2S@vi^0XX@56}cLag(A8v z7G#8BDHsf9P82Ndf!TnQg9iSr7=f{b!)#KeH%BFevjY8zwCC_o_=I~EQ6)G|0BJ`m zHlTzN!yG@R3OBE!M4iYVZ?*kimS=~qjpVwh%V5?g^>)U=(84lkpGp`r15F5P-8AdK zG?V$9lC>}B<0uS+e!JJUk`;IUR0sG%S$(Dl!_8`=5dD`BYa-m==4^{_IJ0uGbIgT0 z;0G8wV7uQ5oR)A=1ZGFWX$|rpII)c|z_$rUT*(sH7bM(c*R73SJJmX79WyQN|nP%PKOf#&r2A?`no0Vw4>dg$u_V3M5%^V@j|e8 zZ@;vgr~lEBsTg;&gU0JQfF*Hdy+`d!#46`$OHmKcaH3JS#zW+80(tBobTRCCyf-rj z%W_E1~Cz)r!HhXpa=Pc&kfTS;M2t+-rQv|;CDub)p<|))#i!K28RVYDjzBj z@MTW1=G~rI<`80a%&=Bgj_jvT=jngf+*_ac{9Z^tSQ)c_v3y zJ6D8o$J8O}FkU51k?3OX!jHAO?>~XL)EG-e0{TP^o!VcXPo*84@dzfvfp&1YO+PKy z@$@wyV9;MKsgf&8_acwM%u*ZS?K<8J!Hk}VoBqrJQ|R39KNP;`1Qw-s2yiXf(3^j9Q`A#pO3WNyhpMOis;)ns_-Vz;1z~JatIU27?0Hb!&vD34@(|Ra zL>K>%lN2OfVI>QuiPo>JioEC(b-2slkhTpbkv+ZKS+clx^L^N9*hvAbWYTA~r#W!ci+I>2%j}zl63Y zhoSQ(2=+uy%Q4p9(k=EZ}`#=MjMo!eqF6%ZW{FVhuWGt=w}T*jUo~vmJ9U8 zP&_;0VOpM6HX-~+w!<4M2Np?&Ggf;DYe^0p1pq#vwL>dB$yv{!c2=xZwr&kX1m8kE z!B#Y_X~m6xh ze)5fl78{Y8YMk^o3BZN40m$d^5nrw_(g8olurQkNPeu!aBQuWC7Pn6;O-dZjTu}X( zvqONBJBnme=Gb&NDn(um0h~`eqlXc-#1&Tp4D0fl0%dQkmRo1AAcp%<<7#_PtoHWw zjT{|rP0KLd?Wy;fT~m|uA(yAwDwjSib50?wOSb^UAL$qqg-*?Cl9p(AUW=H{h34s2S$)n4p zhdIYiO2@RLgqNyR6D_)X%DdU)CxI6BypG+5VEabX(I0|6f;uathh8o6Q)H|68Nd3S za97J<6I?u8_Rv^Zc?X++x*`~ni(u{C1_opNMZatBO@C5C$;c%HTjc(?BztQ^11_5F zisJ9T+XLR8WuTWPf}+M@9^i74m~`L-Twqny4Ob0yzQdCwHrlN-=wGY&(dc~6`ap>q zgXdPO_W4V{|5cIfAq;CoG-gey=X(P$w>y4d;qeE@BjpD z7Qx2dLiSDMs8_}fIPIp)X7J{v1vHNcSUUupxAY~OvNO|RmLt_R8`LvI?^_j~yM>?p z+4yO3e{ST0A7pO_f(T5NZQwblX#8ZZu~ulPVUSQ2bf^2NDZa{PpO+Far(=ZYd*N>F z9}rQzf2bj%w%c0H<^2UeWwo}PLp!;ALvlXT=j>^XT#*ZI(Xu0TdHS`cu^9QPI%xQ< z0m|iE{ng1fGb0U^+wd036{WUjrYY(`?5AK7YUJq6U*B|=C0LKCKW*Q1dsDyaL%g=i zmn4;0pmlRi458(Z2=0{aFuib?a5(gUBxoHLg9jgm=la4$m{A~^T7^ZFSQ>vhh=|FJ ziffh+4hZ6aF1I&Rb@DcdT}LRGw2k0#*!WXn zw=V@(hz6przMHBHweKkoNezX7t*|N&J-X`vPslDcz%_Qa+idQOL)mjYZ^ns+o6sgG zTh&9b2gQ0X@c4j~O^B6D&AuDW%jde!E^GhAztdctg;~L+EWJKYEi{&7Fe^`=<%Y1{ z=FSc!AF@#0UBv80a{h8NuHE-R9IQr$49t)HKNnpDY_P0N7GZ2q`oC^Hln9hNP*5{u(USz^@3?Blj=4#)V@M;+3BVT@+Fjh6OA-WY~rFR(F*t9jd zzWVeW-vGl#XRIE@#Q{cML*6$| zluA>-sMc6N$H24$`ru@}8*HKFYaFrua1j*gaF5#nnM=oTq+#aYM=VU)pu+E6+lUrT zU5RSW2JS5w%P7~f4N<5F5&U!5vk>_{y^hVh2F+OMtzJSnlctD^(6)n!XgQ7s_YCsI9RI{OXVOZw`%* zGUa78y-(Wc0-wP^;q)$a!y9FS;Vf5jRN8%(?cN0Q_oL_B9 z)63${tnAQ}3q?}Bh~R<@X!&8y|bVUNrZBxHTb)gCJ8D>I#!+a?`JMZUAKOf2r~ zaAo2i3UG(#OjOE4r4X+qKbJIK(euc&cBkdw@{CqPS0TjUnm~I7=E8{C;vUvV0oFg+ zvvxrD-vP4liCV&=S-M~DXM%z}D?MPw$>iiOpK-%4K;85`Ll^c&-rRsX0EmT7QN7&T zU&4bzq-yBXW}zxdWmWba;dmc57^&WNY+L=^kMdlBo~6F$#}_*$?-f1;qU1}F-th@_c_U~U)m_j~gv zXmQ1ciKzBjaj}J8e1CK?zw7Bw%+=uheIDuh8li*VpIPt}24HpC;Gq}WtgI0Mc$;4n zPHI0w3q3n*%4~yFJ+V;NNwV8obI~L^7S?(S^y^ae3-VtFy5jEL;K$hr0Q(aBKH1lVN0wMT80Q|PEW<2VQcwfjICV#uAgr4fkL z=#cm?tEIb=Vj~zF8x@X6Ui27wI8x^+xL{Q zj;8>2w%s)jRht^-RP6|%{C;BM@By01sxg0fCa82O@W7~mzu?+LpLW$XqzL%ari&)I zZ!h_((24+P{pk;-EnNL(oO+)Gm5YfVO5hRy^XaL)U@->DNj(-`dl2R`E};0Z!G1zt z%+Ki^z5k9v!4aIbP~5py0kra@9=IXv_8lo8zn9Ww2hQ$UZn;_A^CyGE^OFL!8mu2| z&pT#zCRYwKV;E7{$``#W9@Z|Oas>ZO7dq!I1h?UcN<9Dy1?NP_!2T`rcx9eNgmEmr zh4Ey(u@NjJ_;GUnlgXUQOlfaK{{Li@knO*ESL3$tm$4ivdaR7UbpE7RTevif)lsh> z_Pjln=vxupAc{=m)Kv~owJ9z}Y5)y6jn0fZ0O_G0$!}@V=l#!$_ADOLH00oaG)DuO z{l?r4HJs`3;t#q?n~Py;L`GT_Yq^?BBSgCJaaSOFm&l&*t4+?Rz*{&GfC$VyrqrS3 zaebnB(2A784~mwq>tGE(^*1fyG0aAxKDx68Zf9ZblJ@5l{71C3cj0idGs^P>15BuL zK(@DP+`t5NBBWQ7%74M`bSWilOH&6x3=FI+q4o>Iu-Ru5fhb`FIq7)83wmlK*Y<(m zx5-z1tVd^~uY<0A`Dz46&X&Q%5|K3tvY+nxeSm#PG5`@M*jsCT&HG{s!;S|tZs+)V zsP~E=np~5IGWBg}>qfUPxqt1hnHh_uJvycLo_xA!}Y5jxdQff5Oonr-S)(SO6_z0)aO1@ z#?Uo=>xG^#+F>!i#V+({weq`a36BOACpKaR>}I4YQqhF_;N#l5xHu+) zd)+b&y?aVY>^oahiNG+n1T@eVT8aix8`bc-iDyXMmLP$$Et(96{Z(+hXl>pGuJ3}o zZaDz)=81LgNHMCsM)kkdsxt3{%f-`d?la`3P)T8k0R0JtH+!U%N`*cJU#XO#4>j$| z3=>?Etx_*>+s&yNgRdnVfZiFGEq$vPG;ON3+=JxrZw+QVIXQV(oQCWa(d}GJsl&ou z!Gz2LUpqxXCZ9}xLJ%j za&DiAR8z2G`+(z&>;wWc!LMzz{&2XBmH()B+ckZ|S9a)(pumIn9SBZsaTO+Ux3zFTQ(XPv;KT1nB^7h<;Jhpq?gW=?yo}nQ1H1kvRM)im zctq`LDw_33+H6~^B_l1r7^i{S?EIYfNl=eE|8SN_jyQ%;WN~+h(|UR2c+Gj#-Fo=~ zdK=)>%&01$ECg-gS0TImX1RcWwrjnn^4t2NO(7>A+SFs*LHB(Uk%L3(+mE(OJxKW@ zQ?pCIRLjly>y!K&vtXqpB63c~_i*lZ_Vq#URsOoZ-8Zf(rrmKke{Ir^LJ(GRTFoN= ze?a`&|3diBBzHh`%5_2OxZfwv@w}E7@V#r7}ADgRq?xCvK2L zxhWkwK6e$1wb&HFpmk>JyP~Sgiw428;!n-{6n0nSx$-~it8fzAjqn0-$6;!H!d04=O{=&F~xI3OKd&u_w z2t#5F0s&M(JZ-sk56|(j1K|Q$b8$%^AddX)>ZMP7^l1|uY((u~L)R$ZTmhu&no|{f z1jN7ei}S86MN=MZ2CZ+KUXN6KqX&z%pK1OtJH;v9?S^%N7NvWe~bm zlmm7Moa-=j14&+ui>qT)gx%)nvO_M_F0Yd$`kvfU@jdC(=@%tV{Yb9%R#QhAgp z_RsHfa%!)azE66_%k45d=j&%I6IyG&Z*+cw;pf{NzdK&{`n3Q*+Qjbf7lhueH@Y zhDk<>vjGA7B~Q;Ib<{h7ubI@q`rS8oCP&5cd-`kp8efyRIU&a6LqEC@ecdhAmH@q! zg52Y4b1hWAd2_bXe1Lu#;;!V)V`;y=V-?XQ7ENtHpJv$2TKFn{Fe+1RD^oLS`Y5(cmKLmf$VsV+PJ@m@ z%3vm4u1W2y#dXlr`_-Dcer6nU9D1n_`nzjEi|XJTu{?!7Y;Vpwm-|KchgcB!>Ca<% z7V!Pxt73T>aZ&?ChVbpg@6zkVh()u3fm0z!;r)%fhY&yc`A*q!Ue8@)YrMyQNf7O1 z|6qi}lwz@cnjzrUJf=e&6@8-xwGy5dEYT0lSFR6Sp5rlQSl`rE7^onvjJjckplg^ zMG?NY2Zj{AEKk6%CZrnEsT`VtNbGyVhcOcuUW;&{L0qyAzZ*+EtelHW_3C1v)~zqf zV-w#5A&RAC;?42ZWzp zerhnqOAc1Y8Lq-|csP>#T4hx&;o=|2kXZL;HDR2jsmNq{_JFdjXtjvGkXRAk?$EZr z%EvFN(}0#Fl@6#N#mE+)?d^P&L%Dg>xnoYK^A#*LsfKKRNV-LLpAVNj3>=de%d-hy ztR&yu3SMzcdXz$B2@G)Qm_JgdXzU~2lB+})m~}ZY#JpC*diR-m^T21_V+tSM(+AT3 zi(25O{?Cz@rPFPrAfnp=Sn*jKKj-{>{A|*-h-ZS8Z@J#A`p2@=F?$eJIL*2+x%;bQ z{4ir(qV%kzrmv<9c51#rpiLQ-JAb{=eqz;%e9|4XgfyvzfPyzkA=?&r#r0#fl4Oye zZ=h}IcJ6(mP(aTUzqeV8{w6T}NtQU1J6fAYFLWjF;awC);sBNJ5mfg#6HRGN&0Jh2 z?QWL*-oVyYB{|d9Zgc3FHqF;BLGL1`uA3Ny9eCR>o8;>hhmLI7G!=-w1{2(g4tl5E zQh$^A9`tP%3q_k13Ssno_k8)r{v9<^sF8?*U1z>sj`Abtugt(D{kDU8Cru{Odk!72 z(=Xf8$FWVGyKi}B{=ctbhOA{|lo&Y6j=;>X6`-9;$bsp_an^IG3A6nW8*?|6w zmyOU(ew*tlnPe;?pz3mk+1M?9Lj;u8oOW z&m8@)OrK~?{#|1U5&U!PjU&eI`?1Q-FPizYZH@P z7x{O@y)}8c-4(~)YE*p0)UNBaS=i(nzW{F8mf?hg35{V>6-!-DEmYgY4U|`!^^@ID zH(O%c0;)*<*Q)ks@7{9mP$)OkvcjrM%X1lLElhzAd-DA`pY7rKGW=HHrmtr)`R)nE z8SAI&h27m<`|_xfi?mABL@31l zxm0q8-08lhmE1k*>>1=nUwUfKu8hBWjnN);Vs3prz12AxSzDv>FHn1C;rPZel=t*O zac*}5p+Ol$S8=dg#b&>{{@LpX0I`lkb)XeNx1|3LwcWf;Q9ywp1 zd#;~-ab9^WZH4v8s8;#I^zR!(_@C7Ed7`gHMHGTT6#6ld+1nB=@*;n-VcrMDo!1h* zkf$zC%t`p`8l)3B)V>i%2tHi%J;^ZxrfbK>K3uZNf*?CTW_;b=_3H?CF#3q~=n z(^}3Q%v&CuSw5BxHI8R^x_b#>WWFY@03WHFpZ-mPx-Sa}b-mc((L46-YsMo~!uSd8G zA>pyw4UeAp-v9eA=(lEMmrYR<-MKyWzj^krZ0jh`_=l9YXjUza|b?z?j@I z>%G!D*B@GX38N{G(fx15A?@(b3vvLVCw5 zUdQ3qG>Kl$zyJ9kGS3@xK50!PRP=?aLHFUwm}kQ0NMm+kR@2$VNzFQ)IJmyK8Rs#8 z&WD_TPR-d)zN4wMa#I*l$>D%KYnNYk@&3572*vGOskj2$iIbAQ;8~Vpzf6LYe z*=88BY9-h$STrozmgrl*G7MRHiUPgMi!CCgO?iwg>17;!voe}<&>T-gu54&4*Ttv5_yb;4t_oESwF{~)^kl+J(rq2{++S*V3a#dLnEsbAm>VztUTrYqpo*Y zORH7yTq4+tpd;|ra)?uV`BoJ2CEoQqqOLlXY=&y`9X|I z6NXu`xqi4lw6w4YJ(i!t)WCX)u|r4cLJ@r_JcCY8E0YS_!<;Q+b#36optddSrl~ge^&&jamHA2q3Tqv3>?|rxYG0ZL z>e9K@E*S4P$ZA5j2U@NKk}kYnCrfs(H9lb*BCdpmN}B`}crg#{JmNZzD%72ms~)jO z7bOHd3xXg%7Q;K}PqmRXYFd_@MBAX@?LQs^St{)dlDMH6$40b0nLj*VM|2ZU)aJ;&I{MvJ<%#Tdi4y&BevVh;Q?Ba3s|t z9vPJ_Ue|v?j^HA|YuDCt>TeDrh-3+A--f1E+R%@$vE<2Ss9T-8UH7hz9s4qZ!DY%} z1>npY0jlfPIkoAHVMdM9v)UL>aN?DWtfuXR-KBRQ?dF0E=P`R!llJcld(KtH)&HPi z@{oU~m=t}9roN;k3Q~feJKs3@JcEP-f9qf*#?cEDwr{V6sxy$9ujJAz5$jCoq_Bcpng2*SA}zHGOxWU>oF z=)6kzH7oi~ba(`%yDfQA8EU%y$Jv@x3N{eAL*4x59gPAbJ&1vJDTLI!0skTvk6(>| zXTi7R{qUJRUVR{;>2`9|csA#L zzhR;(=z(jrxS2t?Q2l{h@o3e9!JWxl?(lleiG-`16=C>XuLOSBo^?)?_9Hu>{4vM6 zv#I0Fct(xC#JUuk7-O_A#5iT6o&T-td?tS+s{Oeq^{45WYTik%e5!UXEBuI3Jep;$ zu1}Vx@}c9}-of93!}9B&IXFB2q8$G%e}dnYGFa`w1NMRslN(nvu&ew(GW<{;_hv6mm#`-Ipo<^Lp}*r%!f*Rl%=`h z#Vyj;5UDd}W)7v~t>?oV*Ix-pQOdkg7=MxUqVx4EA|-3a-MDDoZt#p0paQJ9+<9#957KBzEX_9i0+7KndPHp5rCFrq5d%R zu<+U_SRRM06mDslwyl0aCs{KCyo_;5jr^KC(f+OSK9p(DwO(e%o1kEGA}@{Jkd}G{Q`aZ zhs@M;scn1ltD;w?U8nOWi=}1YJ&18Lk3U8=o`$)cQS}J92Thl-lsU)pQ3;>2g@AS9 zn`Nb%>xx`4N5R!GaX8I^40C*=jEAf-{k&Dwm)s_dm1Xpbqa;zG$2{;G6E&VUdrCg2 zce_;XPI`$mOq6B%IG-;AxVk@03~ooScNc!qdM4kc8@%mrIQPaU9liVex7X6jlLeow zX+qRTgiNC4h%JkFj?i`HC$Lmze9y%ZKaq5%g{(U?WazP|z0fu4VnRDRP0`*`@a>Ow zR;XO-R{NDe4&-0S0xCAuTLmS7KPK4P7xcR&4?_oj_l-7}Bi8LxEoTOiqHJc#WGjUk z7|+(9$~7KFcW{#n>Z~DSNRTv#r7)-Ir`PBk@iJMnpvM}(@3&eULSKou z;4?-(2I2ZG#KsWS$5-mczOB!L-c{WB+ptt6?qF5;X6N_}*5o@@T=&24Mj8#er4ulBG2xjzJx7X<}CYBJ45SsbQjLO+62rrlC`dS~(Ht45~psYg0 z*RC&3lqJPZxA-T!D_&2{`(1bF3|+h%OV1bzZ5@UJX&EW6TjkL-Q8Ld+(QzE(Br`{> zmCspqn3=qneOJym$4izrHkdAV;T6e70YpCc8&q!nsaU4uk-FrQY0_|Q68CDBc0$6U zdO!7H2Aw}By<1~c z{lTGhp6g@`SZxWvS{oQvoc@$jg62qcu4B`z#V{yg5`!MgP?9>0UB{q56y|iLZBf-W z!vGjr9Hss4Gjd`!maaQW`Px;51P7+@rATf3i{_0aj20GnSfe~pR@a(W9I5-LtmT(P zNP-Z=nfyv#4GP=W=!nuT%FWf8hEvM z&CHc# zWW%*(8orQVJr=;&0c_0oXN=D0h;aitMwT6n;NA-r^{TvNWUR+SE=}~-ySJWcS#ft1 zPtjg~Wi?k_OM@M}I1>sB5lRM@Hd$5;z8@>{1mnso+`ZC*5Fm5+#N;`jJUpvk;NI71 zCsd$8=O)%o#K z#7)S>X)n=C5qp^z&WXzkJDsFM>zy(Y^~;p#lOzvs1Tqfc^6C5aHbb;8pMv5513i#- z_q!tZ(^Zk9lAkw=3Zsfd}SBd#w0s8acCj3~!-?GC6Hxx-G} z8NIis`i8HVZNO+POsCtwC1~0P2hd8ehV4{x`JA_MJ5Bz!elwQV@~d7D&J`E(I;AEcq92C;v(W|so;HgZBZA;7N)Nl;m^keWaRcAkH0aV zb6#!|v&#TWrwP>!rNtlB)*7p!;9+f^h^o(0Gt03>?zInG2qyalQT#uqb)^DNHt1C{ zGNX3On^62FuDq~2yrOTqX^-2fZ6Me!m2Kp5eZO>$cMpN5H-KlAb!p+h&4nL?AV{74 zfVO^=?oXY9Tki?2XDR`U4OXqe`eXhF%JZiNj{9*hZ_Z9IJR$w)Umc*#x5f>TFA@LB ze;P~uzwhd`|EBz(JNA2Pv8!UTVAU!Wng|p5W&m>_PqhLwLn(HcS!!ja16olZ7EE{i zebzy$eK`aN|2g7A3D!EH+wm}m|M;f>$*;&bn^Z!ng_O{xe@qn;K@e8VXYh2n*Vt zH^A4(_Ju-$SGT4p%cFtXL>R(Xm65&;+wqs3w0NDG3YWcMAHc1nA7*cWgH1S^DnU*v zE=sH}{;Vi7K5L4BlPjb3_BJ!u-ad|uBK;<0)HY;WH#i9lsunP zy{LIzjMT3!7hjEhD9_Gpo|wSOAkQv0KvU3-Wlp#mL~w6?jQD9yQcrq9!ll7}QD*P) z$;Z~}e(oEX5v0WJ%(C=kpBK~;yn_9QH zaE-3-&ep1gHgkYq_8b_H_nc!G8%?ct$W(hWA0*TU=~M5QVpX_VlM9Yat+^CeC$MT|6%!xAQn)OGy*DA z2AlrMt=;c<5w&y$3ZiV={$EFq2Cfb^PV(bglcF z${ObYTyxVWFw<%237b%|>j!lp6G*Bv-8y+zI?RG>GTm3oIJ+YkK2zpad*lyPl1O57LFlApWn8wIhI`_?7m|ZfES1=goyjra-Ul2I^6Mbu7{+w59QrdTI+I!wc?+o@|q&Dhk$@ z%2G@*sp3damm&5A-jK)*!Mf<{{s`&GOAr=rq~HfO2rSMiJURh$XHwF*v729?dvYD3 z!HDZvc$?XZeOxJG;aB}O_HAR?rH!nEDRh*`CyD(ohjy^>dlkdG>L-M4G47qF1qp%B=oIu@vqjp(Ll;LvM| zeiHg`q80AuEM(^BB6I})=V?Z+@e73gXWGd3+i=lQ&!QCbo^DiRodrd|OU$f#JjrX; zbo#Zkq$nDl=tuge@5sAyb~~d>0P6Gpt6hP*F;_yx!8f*#w=6wE15|_jD(Bs-!H#PY zwL`22cZc7WF76b@Qj7@?XdL#dr!=il>LNfdO0)E>*S312%?aWbRc}k9*(){cDv=US zA#!DnHk>;SBMxem={2D*{0Po9k=|r?36RU_E0) zf@chrdFJ1VRJ1uQDwk*6*wS0`d*|1t)RHIFhJ-0Mg3_}pQp3%EzQ5|KT5IXsk8M~_ zz6h}I90I`;D?43|m7}v)b%*;IV@mHt$VquMH-KKzo^R`|W~%H@MKbPApU7?gZPvTq zo~m6P)z`27M4NpE^i6tD)_b&qrDdeuWQb=To45itrLbetCl(Fw{{IRI1Nm*mfA-1l z^ZJ_S0Xs1Z`jER)8pf#RkkNy+Pi0rP7ytBBrJqs ze07}QW`Msx2FP>+{vO7otLgG#;`L9yK?E@!H#Mzv`t9XE?s;U9a#Bi$zSnqfx(m5v|{nUc@ z^j%36P<@FS`J0MZ!Gw&s8+vgQl#3J2T{p!QgcVHQ!ZTEI=AU0d+DtoRaX%gE3gocE zeWy!0wxMqE38d|2k`giG4A)s|%SFW|Z}zW+a;@nYtpK2w=oQ=gmU6rYR#+{#i={3N zwoaiWjzZscS5F#VJu{M|qm@pPz{aa?o`moI&`zjH1Bf4G)69$#k&+OxK{gE7E;f1B zD5joq0j|+Pas(txhIF8z`l53XFnm(ESv$MDbgTva_IK@*WD)N0cI7_S2^X$@S;(N>v)&O^o&#RxnCR1GAJWnrF#$mC?q<(ioiw7SPs7#fGR@NSeUVx z>Si)d6uRqs5B96E>f@R|tnmn6S~%Jd=eM+B%hENRPA*06_lFj~;%>}8x0F0@@h-YN zGjD&<_28*b5B(~ncy6VaeS_uiI zXZ~2TvWy~ERI&R_0>?sD|JLGE9_!=DqPHZvwNX5wi+}W-4n1t?<|-@7lO1b>UbLP%Y#h6EwGRZu8C<@p1JXp8v;nkZk9zsL3d(!|4nE6BjIdH z__9lCO|vq2KI~zR8%}>hHX|3H++oyDaS-Po{d0AG+LisUq*0*=pBXpS38Gmxo`5pu zB~FC>yY%|P=I%2aFS#eM(LcEp=uU*>`r~Zm#oo_um!F|;W?CF9aAo4jnbbXPmbQ!? zpk%oQSYxZkEm-<|WlmTNp)Tam>hzA8;rT4FU2mMDVq+c?F|4Fmp@;46Q{it3Pmd>3 zAGM$VZwB)9i|?b_tiHhAM}AcWA=aL6etHsi4piy}#Z(`RJ=%P+a{xZ6N80J48R)(- z>mey(%mW(1*1kpv6%tYYEx=-6YLYAHd!4O*&JFAiy^s;rLwz&pXXYU5pW*KwPUn^; zU>;{B>>|_8=o!Eq!Xz1A7Can_=mG8bcs`6G%&Jl)Y=n~vzK8Zm4FknGm5TZ(emJ-r zvrD~`0kkp)gF;=G2J;%eQ(XmB9XVV(awQj$CU_#~w<$8KtqwOf4Jj)PZit-@G`{6% z2!RHHItXRd;$dOht`<1KD6@V2{h6lz;3K)OFF_R?mPc}3*%HT>m(bgh1Sa25irZX3 z5qgo$Skt>VD4@mE4`<=>NC+*2Qh_i7GM$RW+fp50v~b$Ra!_50VKJT>taQ31$7!q) z6~KVf_cVbdLa%Jh(>uxdm&YPeE*6fkbS@c{9OxKN02J>WC+L_W7IGfNw{k+5f$Y~5 z5$Sf5=ERs18q-Ei#n6q_=12)%+N$ThVjVS&mRoea?4QD9|IzF^DWNRK5|EA|)IB!- zEY9DE>1Q(DtR!rxKJ9Cyq)P1HD9L`;S9mT#iHFzT~>#nuOwoX+-ZG0jmH--ySK5+7JQDS(;04@oxCW(bdHw%nY~{30I6T;0Wp41hBNf6B^Wn z>H`c`Qr3LARe8biaW6V)dnmhad#J;*WUONSCrQ*+-GDf~v~h6ZItXzK8!Y*Z zgE9>JTWF=GSPn`)z#GH{q9UB|v0ydkfB0D|FMJiCs$P_}VrYcIyNvLxolc@SnQWmj zBQK}w`=t{b>C}@a53u0LBGj5ZyL4-}|D0-{<1GF_4D{o89cWT5@KAcLBr-NSl8v<5 zxcN!Tp4#_gWn#y5F?;(u1rG_Vl0qsVbN0$a+r53Oo;~dKEr=7F`g9iQ6MEyn%+%H# z?sJ_cRq1Nz1%Enf-tM~NZV?TVJj+Rp8dRB`<=-qwGohqs%fDJ?Kzh-#+vUkTA9*E= zT|FHO&U!_AnJtNovfLs3I}piXeDj4&#G@rc+y2JTKyNLHU;C}FNZ|RF1&s@N7w%D$ z##x?!8TtQ}zcT)lzdX|uDMh)EAqLb~&ZQ4o{<}{PSoUg%UHe==rI3q}CF1P+(K205 z&^|K&k(|_|q~-m| zkr)LTZ&CYd%g|J9mT%vS?9BOp79Hjl2TCLwGwAwPE&{uL*%AidhntX=HX`o=d{==a zrb~b1(NABW8W1X+)GQ|w1SqEdmV)*tns%l~6RZa+pzuXwP4u@~>I3atTQ~pjKxrNi(PmSXEdkSR?tTx*?(#+1KN45@qgdxi%h3Cq&*+Tv*!7b`Sfq z#>FwvxB1O2m-mE-bNW#LtjzZoZB`DSP4&n((AGq{5{&l>3x&J)ix8tk*$&J-jTem8=HmaLf07rjmP$APP z-2U~qS@JlW3i)PkEayoEzS=Dwd)Nkjm!l#R-_GjLoB z5bKCO%C73a6Ba2UTZ(dG)InWyHq}9>GuIV;0@qQ;^PmUkDGGYR2Wz{VCU6Nau*NUa zWq$qSaR}u3z~441fYZ`Aq7p!dtz}ulP+UHLe&-(ve6n)F0;$x*JI?9^W3v?gmGAt7 z!sX$1yjVWd<0JxYWpFAI#*-*D7N@Huf#PXWIX7%auG>-Um1g-{d7tqgZ-605I-M`1 zW7YjX9wNai>~>_{gxV$+=b{O1i8BLpFtVRO3@qJc=zcTYVcM~s+jV46m1X?i0^O{>RPjzAfU_(>+EI>*hk+v)~dJhqB{g{m*4?!WY$Ube#gp)viBYd1y+vN8z%^qCascNjpXIY_PHKIN=b3IwA5 zm4e$QRybaSps(g~kBxDatb@rtrW8_B0nvtqZ|GE9=uuC|WgMX-Qos>gZoVp!0Xop4 zZ1mf;z3#TIQ~?Z*qli{WVNAs2Q>LZA8dQzU7yYq^__3NoVW4(Y*GoO>OjtchL3ca_ z04?{6FoE4SYjyCn0Jl>;mCJV0?|Pm9YgPe>m(vZLX=&`YrbvrxqpH`#h!1jRD`pzq z@I=)XWu60r3KHA7k!dK5kTm0bsqqZWjAS0zF z%ou0~(Hq+!e4sD6H1fJLHJNrcbS(F}#nv&}p1z{@tuE2ltgo2_=BfGs56TuO3>rOY z>x!G)F5CgarI}6Nim1oGntEfih*?cMy zR0|Cj(v&a6k7i^vBi*)Rt8;k{53Eyio12;%C|&xEXE0qGgEr_WsDn@o;t%QhKF;9! zFGUiYM})Vp+6hl;WUGkmS>U))_qwH53lf&GI(an1R;^vn_l!OG>hgO!K^TAUOiW$+ zP{x@znsrf9FSp?79vWUbJt^|HiIkEO1F*6*B|fKhpHyn5)`5cWW%O-?hyk72AQG5c zfnVL%@|^KbwXix93+c;JdT9l_CIQY9j?WNFX z_7~uaL9FU{ZS>5g-lo@qam>@qvH6;W&%A4S< zdP@<#{8~#61VAVIX@4@ddf62;e}9v9Ckg^9{=69la4C*eB4GkHe{6HkKo!!2V6r97 zJ(4&it~MB^L{6_ZN-Gw;@J9&Lu-EteD{`R0v40wLqiGT-JXZVG7rk;=LnGDpCxNbu z<%UwNC3=^Yk#R;zfWO}{pq%MbDxbk}?i`JDG%*^bo=jL}f&^>s69i0>PkpldR7hMu z(C(-NFS0o-gtKh4>>&J5j`JK`=tfDXsf*yO6URqzxL_|%>NhL&`kPw#4-8dS`6|x) zT*nMgc(_Dk_+kNITRN3ND1$ur^|2v?xwS7iS5FpB{`O(;JEh6iha%mPur&fO?n=lS z5}a65WAUI937O|4+5*)%qBC5WqSDgvE{etB=Ii=iND^|-%Flj>*WvMIWB+aIj+$d? zuVp!pLpoS@X2k0@TT8{41$$ydb1479M0!2AGM~!t520RtU*j;Trg&AGa-UgA5*C$` z&RCMiQgdw-sj_i~%}CBe<(Ppl&NdU~JbI$#_E$UAp#^0IB+b;_Iv9(cFVvN07uRHW zdhK0+W+C;9lgG@6ho>itZyj43-2}I@uDdb^-ApLl2w|SaWkU{@7?uX-Un-gK8% z*7jl~o`3v&z4Lor7;On6pUa6Gltpf5jrQ9qe1@q_qNUa$iKWlP*UZ|$SeX5;?dwtU z<~UClQB;B%0W?UHc!7<7dSuQHL_otNppPiRo|58j+hN;^N}PTY{Vx6B?2L2Sfc=B^ z(zU)(-N}T$hh0c5z3 zzX^vw?!Nim+fNrgOM?*GQ#>tGTr2fOADS;F`(p3E8*;VUQKcb0^Au5gnJ!{`Lx#V-&RHL0kWU&i!tMTfa6%t3GN_*W}j>N?S zNtT3uM&fE&V*&b5DD(^G#F9owF~RBe(L(g!Z)Ro!x_tI~gfuYJ2?6LNU1@An6y29H z)&S{FeQ+TF!CwR6@FTUVj+{ZW(;lyQd?*4dH{^3ojX*k1N5JaQdu`o*wx{Z`jCC8v zTUSE=_7bmqj? z!r4?enH`6d+B8$1@DbsseF{4eBlb)3Cmf7ItJAy5KLsge7ZdIc$C|$ia-x+DDqZH> z`y0QHH1Ot#=l*c8%|dd$Ue_h2q{K9hmQUsu(o6egp9CK3FQKnSJs|j6k`L2K|0acn zPCJ%~MwvnJx&TZ%z7`qtH(@>V7OaQJry1RJwK`fLjenFE>_;#+b25}0r0M+dC@;^+ zy~B6?0Y$ z`r0YYPlNXabTSSY=hK7{WyX&|(^&K=T6t@U*silTe$ICQ59T5C*r-A!9m~?&2 zAd6=fc^Pd#K4!YtCju&GkQhwW*H;d5A^R)sY+}5_Cu09yfqlSzBEQnyRFwaL8~i3W z^2#%RzwsT%4Mk3I>!4b<1;)v#L1w-GW%2OGiL4Wx{+OT1?HbKjr)k0W*p#CEr9^02m*bOo9c$HXdBa-M@z{QYPaZPuQtXA3a0_h+PPQAn$ z%e+iVofY<3SqDMU#^EEevC1hI`l@4CX4r?Fkg*i%<%p63K(RT^Q=`|8^Ht)@y}}iC zMSiXHc!6(0FVEK->@IvZ0!`3gw7@~rFIsDQtL4)&5G2BvGpZNe#_;%$sAiyC|1VJ6 z+8RAuz$qO+@7mP(_#XCc&GNU-^d>%nu2MY&)Jvj)b3s>2Kvp8LM%kwbC`t(M`lRiN z7mxugL>+GHc&k@$i?EC_7$o{~w^A(Vi&*MJMkAokpI~T^y%mM?R5n30 z`{D`^Uvz_8;yGpMiLr{2^w8dY^xaR*jBT7+Pm0{|ZBr}B)+vvPgKgqI9-xi?|00?H zHRk{>u35kBB7p}tu+QH~Ab|Z0qrB#OOnX=lD80^ed>zBV^M(6kFDn_vCkXR>UFejx z06K-n1u>=WjW}$%+#o`u(roXXxwGB$qs6~agyaOZnUK|m^QJ-<#E&2+Ca!Pk*V&dB z6I!K1WycE;xh3?L6rRF^{K~uN%-}01c@sRx3BQ8!iRS9-uGM(91`n^%BMdIe~&sv|0N;DXAaFsxv@7DnJwkxJ= zQwj3SCR^GA+w&2~9m}cum~-SS;beO^$S<%L&rP>+AO+Lgn*E28qH%sN_uo6>QkZO4 zwM4;ieMtUphu;l=ahN=m(`+*%2qV&Z#j@Jb)^ z8)O>VQTc%!wJU6}Gqxsdtbb#%yaM!^aiW<7vNX5G!B+1axNld&##oj~+-VT%o zM*9xDI5hfG+B!4pAbSGr(YMogtIh+&LRKqogdbBo=L_HW@fg2`|IuR~Q9`?WGY%jd__L)a zaIw)J4rbkG%V=9>jymF1zC4D-4FCy&D_PY!$ti?B!!8F&TqMKEFBu|?Av--h+2nR< zsKmvs)u)+gutx3goi&5u8`Z6VNgV|8S^+v$>UZA<>K=#4&lf(+0>85Ft)EcrD2E-N z7OvS@80^c+Q_UD*1arBQ{Qc04JIX;>x~k=IQYEp1kqR z6@S!=JMnL1v7t5Mf%;KO^AoFk-d}4Vxf*?_NOfOrMmKloEO^HTr&p7v@Q+G{0oKmB zSA;mGNH{751$S_aHH+y2S$_uV&8B|${J4Pqq}^n zc-Dl=x+lY>;x}`XiUUbdLYM-x6VzLO{CkY~=vCCRb%4}q%Ux7X+*`}aUX@^K+~D9z_XWL z`r8DT_Qrw-Cu+`#U=;Kn&DLLmH3n_npB$n7xEQDpoyI@x##Ky7^A~#srQ(RezUWCu zeMD6@fl4=^zf)bqe>shN>~{z(r}3@bTTb-TV2veNvFgecbU6k}p9H*K2!(31IMRLd zdX+G9#hBC9CKuSFG=7&7-j|?1 z|H9EhndzMpKpXgCkv~ly%dmQ$jOK4rm|dDVR?>XUE~ea~*nV#G6_!TtThH0_1g=VB zo{7|+Xkm?n$*+FXc<6z8qxcKeTn<4+%gC?{LfRkC74&=9kvjfK&CNmy2(I&Sr3@=j zpy{O_g5|S-4h*75_}~$M$MKH))*u+H#12GBB(z_7tvlUXrqQ*zsX4soTLehFlDlo5 z;jiatpFy>aM~;-;_wT?C?%?T1w7GmDRR$q+9doGC&9=JqEkEqV#&%`FqhVGL=bE1n;t%3$`UL~cC>fxa-#CsDsHQ}XJk?rH9c~5T z1gImD=B$h(*00(hLHb$yHTM;jm8+JA#ZLvc2WDYQWuVo_3_8=0kYde_kG_eB4@p0b zt1441x>qLH^dO&n=9Ff(CDl4+O?tCrAR<4P?-_`)m;nMSZF<|P7)$;4^O2wzt_Q;A z)_Dv3AAKIhw_ImwC!ONkE3;4s;HH>wnS&@qfHlW`-M} z%^bxt@Rb=pyvG+CZPcCPWyNS2DRAY8}!TL zpp~VjB=Nn(Ujx_6Z^SIQXwSegS=7^JX4Bskuk~!Y*7`YZj2<;3(8Xo{qBt@~r$mU< z^B}H2g!7~M13zw%jJT3=CZVXIS&}vUv{W;oML$c><3lKj5i>t$8fOqye15-+UTn|G z%KX?L-44axg8<*mf86i(@Qiu5l|b=B^DhU`K%Q$V7=tZ&9AC7V(NJotEah}=|CRFM z;v%$w^gj^E;5e#)3SyK?1tZk_CRx@P%c3|ZY~Jf06lYM=-m*A(OpeJgtBg}@$jz*~ z$Em2Qztg1ke?qCMv0=Vt3b5q)h^ZxRa9VJ+Y@Z|rZ%qbOK_Xh{m97ckHsW+w-A$O0 zAKGf(guYvZU&_ON>^!eVnTc0g4`y%fD=IP$#(tBrv(iflC*4yaOrDb31?&zO&4lk< ze*kOaYgy~@Zy@0cs=oEo!viN^cUpnvFOA7$QEMZNyo3_h%q5{;$fJal z;A8qhUvZ4&R`dhy0fn(TFRN>vt?LhMap=U6My^!vd^)J-j^&`Qyw)&%m++WZk|_YG zA7OddBjWe*ROm);d7o6cr^q zP#Gf?Z(9~5J66v2eV1m0J-S*%RZ5SPD{?C&#^_ieY<^;6-fR)#|Y zWlO(XWEgvlY`kxa(_oF7G7&QDYht$35WC!Hz0_O%9k6QW0bhTc38TpN$~W7RlozAr z|BmS>C=$U@FFgXJ@c1Q!&rZK0ZfP%^du)LT6dc)hI7Zq) zU!51e#>-uGwp%HM^Q8s&XJ-sFa2WY(vd3yiPcISLOwSr}Ji;8g>9-(|gfhINKK>;6 zb7NSh6>>f%*^XtTV)2E8fRn26D{Rj5NaI%dpF{{fcImltZ;jR6j7jO17paTiT)bf5`I7w9%Q&XG zU@8@D0PS9Xg$enCVqnvltBq#x@EE;m$U>uVZ?l-)A*o%fdk^GK*_F@XDaFx)bZ#19 zvY7AxSO8S@q6^Dh`uW~`Jr6=}&-(QqDwhYJ{8XSbTh@0;{q{5=va z;EnH)b(G_$=j(-&^<_%`d!oa%h46S|l=>O*uaZWq39PI5s<3zi1fkI{SGU_KCtY8g z8+@60SH%JU-mBp4q_EWYZJ-6?<2z+dPkvd<%aj?)Kh8z{C7U6G7n8SA`w`67W`rWS zir%UAC31oX03+N%9Q>TpXiyH;R&5=H^EOe#I{!W0y_+k4dE62GX}aX9$-227gP|M; z(g{K2#dP+|ku=NE`Wu%4(R8$3Tx(8{{NP-kCY)3I=0^-3#pD1zrm`bFyvsecWa$fP z-;z2X7%#vHTfr5m(29nB2eT>$sOl`v1_g7yia%G%+VWrJEHr5U5{4p-n*(f?V6_Fw zj!c++J%24p$&CcA$~P*@XC*LhzI6I+#3?VeDV5|Y)RSMk|67afR`4yd`BnZ689*mC z%`;ny`)&UiTmn@F3h zZvMVn$gzFJ$by?Hmd{yVa&(KUSM$1trfDQoz+j`3RvQ{-JS#LSMa!I_!=4_R;{~%X z=6cn|v0%G}gHrFsgkZ%sSB2ld8N9e;=}ZtREJ}7zx6fXq%F~HPOTTigeIC21y44kv zv-ht;b;A=S3p3X{ui>hLB^^7~@Q&)a{OOhF`+8SOr*NmFzaurzn;(V3&)R{jB5QXb zlIH6MI$Lu}m1@exHzk5~dd&c%wiY+;TlQ}=lAWcM!{g6!u8wzPXH$iHUOrR$yzF;^ zqFN)xKQn6KBRg`+>%7yXsQtS37S;h�djJ=yX5PD|*&{}r~- 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 e@BOQp(V8z0)k3+3?LzmbPp&>w=fK?(%l0L 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

- - {process.env.NEXT_PUBLIC_PROWLER_RELEASE_VERSION} - +
+ {process.env.NEXT_PUBLIC_PROWLER_RELEASE_VERSION} + {process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && ( + <> + + + + + Service Status + + + + )} +
); }; From b55f8efed19884f3bc63c9c1edb50bf558907088 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 8 Apr 2025 08:20:43 -0400 Subject: [PATCH 129/359] fix: handle errors in AWS, Azure, and GCP (#7456) --- api/src/backend/config/settings/sentry.py | 6 +++ .../redshift_cluster_public_access.py | 3 +- .../containerregistry_service.py | 3 -- .../services/keyvault/keyvault_service.py | 11 ++++-- .../azure/services/monitor/monitor_service.py | 2 +- .../azure/services/network/network_service.py | 39 ++++++++++++++++--- ...torage_bucket_log_retention_policy_lock.py | 2 +- .../redshift_cluster_public_access_test.py | 4 +- 8 files changed, 52 insertions(+), 18 deletions(-) diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py index f6ac512cf2..89c77feba5 100644 --- a/api/src/backend/config/settings/sentry.py +++ b/api/src/backend/config/settings/sentry.py @@ -33,6 +33,10 @@ IGNORED_EXCEPTIONS = [ "ValidationException", "AWSSecretAccessKeyInvalidError", "InvalidAction", + "InvalidRequestException", + "RequestExpired", + "ConnectionClosedError", + "HTTPSConnectionPool", "Pool is closed", # The following comes from urllib3: eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed. # Authentication Errors from GCP "ClientAuthenticationError", @@ -41,6 +45,8 @@ IGNORED_EXCEPTIONS = [ "Permission denied to get service", "API has not been used in project", "HttpError 404 when requesting", + "HttpError 403 when requesting", + "HttpError 400 when requesting", "GCPNoAccesibleProjectsError", # Authentication Errors from Azure "ClientAuthenticationError", diff --git a/prowler/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access.py b/prowler/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access.py index 2b4e00c8d3..275d36da26 100644 --- a/prowler/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access.py +++ b/prowler/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access.py @@ -19,7 +19,8 @@ class redshift_cluster_public_access(Check): report.status_extended = f"Redshift Cluster {cluster.id} has the endpoint {cluster.endpoint_address} set as publicly accessible but is not publicly exposed." # 2. Check if Redshift Cluster is in a public subnet if any( - subnet in vpc_client.subnets and vpc_client.subnets[subnet].public + subnet in vpc_client.vpc_subnets + and vpc_client.vpc_subnets[subnet].public for subnet in cluster.subnets ): report.status_extended = f"Redshift Cluster {cluster.id} has the endpoint {cluster.endpoint_address} set as publicly accessible in a public subnet but is not publicly exposed." diff --git a/prowler/providers/azure/services/containerregistry/containerregistry_service.py b/prowler/providers/azure/services/containerregistry/containerregistry_service.py index 287d18203f..e0004429f0 100644 --- a/prowler/providers/azure/services/containerregistry/containerregistry_service.py +++ b/prowler/providers/azure/services/containerregistry/containerregistry_service.py @@ -46,9 +46,6 @@ class ContainerRegistry(AzureService): admin_user_enabled=getattr( registry, "admin_user_enabled", False ), - network_rule_set=getattr( - registry, "network_rule_set", None - ), monitor_diagnostic_settings=self._get_registry_monitor_settings( registry.name, resource_group, subscription ), diff --git a/prowler/providers/azure/services/keyvault/keyvault_service.py b/prowler/providers/azure/services/keyvault/keyvault_service.py index 3a2cc1bf69..ccee275282 100644 --- a/prowler/providers/azure/services/keyvault/keyvault_service.py +++ b/prowler/providers/azure/services/keyvault/keyvault_service.py @@ -53,10 +53,13 @@ class KeyVault(AzureService): ), private_endpoint_connections=[ PrivateEndpointConnection(id=conn.id) - for conn in getattr( - keyvault_properties, - "private_endpoint_connections", - [], + for conn in ( + getattr( + keyvault_properties, + "private_endpoint_connections", + [], + ) + or [] ) ], enable_soft_delete=getattr( diff --git a/prowler/providers/azure/services/monitor/monitor_service.py b/prowler/providers/azure/services/monitor/monitor_service.py index c0239e467b..7f5b9c8232 100644 --- a/prowler/providers/azure/services/monitor/monitor_service.py +++ b/prowler/providers/azure/services/monitor/monitor_service.py @@ -53,7 +53,7 @@ class Monitor(AzureService): category_group=log_settings.category_group, enabled=log_settings.enabled, ) - for log_settings in getattr(setting, "logs", []) + for log_settings in (getattr(setting, "logs", []) or []) ], storage_account_id=setting.storage_account_id, ) diff --git a/prowler/providers/azure/services/network/network_service.py b/prowler/providers/azure/services/network/network_service.py index fb9af1af3a..c6464133da 100644 --- a/prowler/providers/azure/services/network/network_service.py +++ b/prowler/providers/azure/services/network/network_service.py @@ -1,6 +1,8 @@ +import re from dataclasses import dataclass from typing import List, Optional +from azure.core.exceptions import ResourceNotFoundError from azure.mgmt.network import NetworkManagementClient from prowler.lib.logger import logger @@ -64,14 +66,22 @@ class Network(AzureService): network_watchers.update({subscription: []}) network_watchers_list = client.network_watchers.list_all() for network_watcher in network_watchers_list: - flow_logs = self._get_flow_logs(subscription, network_watcher.name) + flow_logs = self._get_flow_logs( + subscription, network_watcher.name, network_watcher.id + ) network_watchers[subscription].append( NetworkWatcher( id=network_watcher.id, name=network_watcher.name, location=network_watcher.location, flow_logs=[ - FlowLog(id=flow_log.id) for flow_log in flow_logs + FlowLog( + id=flow_log.id, + name=flow_log.name, + enabled=flow_log.properties.enabled, + retention_policy=flow_log.properties.retentionPolicy, + ) + for flow_log in flow_logs ], ) ) @@ -82,12 +92,29 @@ class Network(AzureService): ) return network_watchers - def _get_flow_logs(self, subscription, network_watcher_name): + def _get_flow_logs(self, subscription, network_watcher_name, network_watcher_id): logger.info("Network - Getting Flow Logs...") client = self.clients[subscription] - resource_group = "NetworkWatcherRG" - flow_logs = client.flow_logs.list(resource_group, network_watcher_name) - return flow_logs + match = re.search(r"/resourceGroups/(?P[^/]+)/", network_watcher_id) + if not match: + logger.error( + f"Could not extract resource group from ID: {network_watcher_id}" + ) + return [] + resource_group = match.group("rg") + try: + flow_logs = client.flow_logs.list(resource_group, network_watcher_name) + return flow_logs + except ResourceNotFoundError as error: + logger.warning( + f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return [] + except Exception as error: + logger.error( + f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return [] def _get_bastion_hosts(self): logger.info("Network - Getting Bastion Hosts...") diff --git a/prowler/providers/gcp/services/cloudstorage/cloudstorage_bucket_log_retention_policy_lock/cloudstorage_bucket_log_retention_policy_lock.py b/prowler/providers/gcp/services/cloudstorage/cloudstorage_bucket_log_retention_policy_lock/cloudstorage_bucket_log_retention_policy_lock.py index c712ac0e0a..180dc6462f 100644 --- a/prowler/providers/gcp/services/cloudstorage/cloudstorage_bucket_log_retention_policy_lock/cloudstorage_bucket_log_retention_policy_lock.py +++ b/prowler/providers/gcp/services/cloudstorage/cloudstorage_bucket_log_retention_policy_lock/cloudstorage_bucket_log_retention_policy_lock.py @@ -23,7 +23,7 @@ class cloudstorage_bucket_log_retention_policy_lock(Check): if bucket.retention_policy: report.status = "FAIL" report.status_extended = f"Log Sink Bucket {bucket.name} has no Retention Policy but without Bucket Lock." - if bucket.retention_policy["isLocked"]: + if bucket.retention_policy.get("isLocked", False): report.status = "PASS" report.status_extended = f"Log Sink Bucket {bucket.name} has a Retention Policy with Bucket Lock." findings.append(report) diff --git a/tests/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access_test.py b/tests/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access_test.py index 816f52489a..9e7f9dc103 100644 --- a/tests/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access_test.py +++ b/tests/providers/aws/services/redshift/redshift_cluster_public_access/redshift_cluster_public_access_test.py @@ -206,7 +206,7 @@ class Test_redshift_cluster_public_access: ) ) vpc_client = mock.MagicMock - vpc_client.subnets = {"subnet-123456": mock.MagicMock(public=True)} + vpc_client.vpc_subnets = {"subnet-123456": mock.MagicMock(public=True)} ec2_client = mock.MagicMock aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) @@ -260,7 +260,7 @@ class Test_redshift_cluster_public_access: ) ) vpc_client = mock.MagicMock - vpc_client.subnets = {"subnet-123456": mock.MagicMock(public=True)} + vpc_client.vpc_subnets = {"subnet-123456": mock.MagicMock(public=True)} ec2_client = mock.MagicMock ec2_client.security_groups = { f"arn:aws:ec2:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:security-group/sg-123456": mock.MagicMock( From e0c417a466000f93e2db7c20057e99952ccd9211 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 8 Apr 2025 18:34:24 +0545 Subject: [PATCH 130/359] fix(action): Use poetry > v2 (#7472) --- .github/workflows/sdk-build-lint-push-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml index 67343650d9..e29d91604e 100644 --- a/.github/workflows/sdk-build-lint-push-containers.yml +++ b/.github/workflows/sdk-build-lint-push-containers.yml @@ -68,7 +68,7 @@ jobs: - name: Install Poetry run: | - pipx install poetry==1.8.5 + pipx install poetry==2.* pipx inject poetry poetry-bumpversion - name: Get Prowler version From e57930d6c29b6669e6e7b621f0f4e462c9711f28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:38:18 -0400 Subject: [PATCH 131/359] chore(deps): bump github/codeql-action from 3.28.13 to 3.28.15 (#7463) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-codeql.yml | 4 ++-- .github/workflows/sdk-codeql.yml | 4 ++-- .github/workflows/ui-codeql.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml index eac9e55c2b..df5c1456a1 100644 --- a/.github/workflows/api-codeql.yml +++ b/.github/workflows/api-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/api-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index b68dd5d405..cb21358991 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -54,12 +54,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/sdk-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml index fd623c3619..29d1fe600d 100644 --- a/.github/workflows/ui-codeql.yml +++ b/.github/workflows/ui-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/ui-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: category: "/language:${{matrix.language}}" From 62bf2fbb9cd3d23ccf5289b9dbff9106fe9e565b Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Tue, 8 Apr 2025 16:21:42 +0200 Subject: [PATCH 132/359] chore(regions_update): Changes in regions for AWS services (#7467) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index fa4f83b4cc..5bcf316f5c 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -6360,6 +6360,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -6373,6 +6374,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -7335,6 +7337,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -7348,6 +7351,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 11e834f63926b9351109b6fcd0ab5212d0d2eb9e Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 8 Apr 2025 17:40:39 +0200 Subject: [PATCH 133/359] feat: update the NextJS version to the latest (#7473) --- ui/package-lock.json | 88 ++++++++++++++++++++++---------------------- ui/package.json | 2 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 6c22dad646..8d222871e0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,7 +36,7 @@ "jose": "^5.9.3", "jwt-decode": "^4.0.0", "lucide-react": "^0.471.0", - "next": "^14.2.25", + "next": "^14.2.26", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", "radix-ui": "^1.1.3", @@ -985,9 +985,9 @@ } }, "node_modules/@next/env": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.25.tgz", - "integrity": "sha512-JnzQ2cExDeG7FxJwqAksZ3aqVJrHjFwZQAEJ9gQZSoEhIow7SNoKZzju/AwQ+PLIR4NY8V0rhcVozx/2izDO0w==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.27.tgz", + "integrity": "sha512-VLGHu7aBMK0rmSEPjx6qb4njGYfEfN5HpeYV32II1dNZZvPxqa+RfWVgPf4q6hmicavceAGeQneTxofx7Zm/yw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1001,9 +1001,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.25.tgz", - "integrity": "sha512-09clWInF1YRd6le00vt750s3m7SEYNehz9C4PUcSu3bAdCTpjIV4aTYQZ25Ehrr83VR1rZeqtKUPWSI7GfuKZQ==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.27.tgz", + "integrity": "sha512-WKJsKqY1f8NkwcfVbUtoTjJ5e8Q2kEFhjM7tVFA3jqesetBR2EegUTed1Ov7lZebQ7XRrphAg665egiCLc9+Iw==", "cpu": [ "arm64" ], @@ -1017,9 +1017,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.25.tgz", - "integrity": "sha512-V+iYM/QR+aYeJl3/FWWU/7Ix4b07ovsQ5IbkwgUK29pTHmq+5UxeDr7/dphvtXEq5pLB/PucfcBNh9KZ8vWbug==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.27.tgz", + "integrity": "sha512-fsXAM07rt7FQ/dpPFk+YZ8LVQ48xP37KzPFAwdQFmVzNLgizdUyNSg9zwu7l0ziMtHFBofYgBXayg9qAxIhorQ==", "cpu": [ "x64" ], @@ -1033,9 +1033,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.25.tgz", - "integrity": "sha512-LFnV2899PJZAIEHQ4IMmZIgL0FBieh5keMnriMY1cK7ompR+JUd24xeTtKkcaw8QmxmEdhoE5Mu9dPSuDBgtTg==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.27.tgz", + "integrity": "sha512-yMIvV5nTOk4p0TDhd9DU6QswEm8YjZnr1o9ZI7A6jh25JHvPsIvjgyTVSlnrGFKlNNtOOJCIv5mwVU7+4VZvsg==", "cpu": [ "arm64" ], @@ -1049,9 +1049,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.25.tgz", - "integrity": "sha512-QC5y5PPTmtqFExcKWKYgUNkHeHE/z3lUsu83di488nyP0ZzQ3Yse2G6TCxz6nNsQwgAx1BehAJTZez+UQxzLfw==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.27.tgz", + "integrity": "sha512-gpOtTwE9GUkp+VNPwTYFn1fN1UINQTulbgO8UJzBgi77g/+T+yQxfBsKUy2H96aKjoMT/AYfn3yyomNXXVoZZg==", "cpu": [ "arm64" ], @@ -1065,9 +1065,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.25.tgz", - "integrity": "sha512-y6/ML4b9eQ2D/56wqatTJN5/JR8/xdObU2Fb1RBidnrr450HLCKr6IJZbPqbv7NXmje61UyxjF5kvSajvjye5w==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.27.tgz", + "integrity": "sha512-b7bogYfYyutEhyDST5qpBkmVENZz1mVOO2632KerJjwWgr2cdycAPU33VmpTVvTs/fT8+oeoUuZ31aQV6cUhpw==", "cpu": [ "x64" ], @@ -1081,9 +1081,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.25.tgz", - "integrity": "sha512-sPX0TSXHGUOZFvv96GoBXpB3w4emMqKeMgemrSxI7A6l55VBJp/RKYLwZIB9JxSqYPApqiREaIIap+wWq0RU8w==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.27.tgz", + "integrity": "sha512-yGZX038wBDSRJ7tbZ6OFZtCUvLXZDVpw9rEgNUK/0PL++65hENaiMXhxJtupeCFqzHdMuJwrCnEW29saF4NmEw==", "cpu": [ "x64" ], @@ -1097,9 +1097,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.25.tgz", - "integrity": "sha512-ReO9S5hkA1DU2cFCsGoOEp7WJkhFzNbU/3VUF6XxNGUCQChyug6hZdYL/istQgfT/GWE6PNIg9cm784OI4ddxQ==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.27.tgz", + "integrity": "sha512-yRY9RzPpk+Jex4DthdKja8C3evh6jB+22AeVd6yTbcnGAFGXQWJTs6DfEcEfeFpqIEcIGbWYq7pinz6vRv7tJA==", "cpu": [ "arm64" ], @@ -1113,9 +1113,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.25.tgz", - "integrity": "sha512-DZ/gc0o9neuCDyD5IumyTGHVun2dCox5TfPQI/BJTYwpSNYM3CZDI4i6TOdjeq1JMo+Ug4kPSMuZdwsycwFbAw==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.27.tgz", + "integrity": "sha512-VSqDGpoKoUgkE2Ba4/89ZchktDOwPhKy3HgQgTf3gOhK/ZEibujLJN4qzp3rSIadn4cXUID3PmuEEM6uRPA7nQ==", "cpu": [ "ia32" ], @@ -1129,9 +1129,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.25.tgz", - "integrity": "sha512-KSznmS6eFjQ9RJ1nEc66kJvtGIL1iZMYmGEXsZPh2YtnLtqrgdVvKXJY2ScjjoFnG6nGLyPFR0UiEvDwVah4Tw==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.27.tgz", + "integrity": "sha512-bK46G4uS5SVlq88FnxyupRuuaCfHPtB/7heBRAZCiHD9GdVktadjiQPCzlXWTKgv6pJxP8bE7J9GGDwodtn9Mw==", "cpu": [ "x64" ], @@ -12236,12 +12236,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.25", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.25.tgz", - "integrity": "sha512-N5M7xMc4wSb4IkPvEV5X2BRRXUmhVHNyaXwEM86+voXthSZz8ZiRyQW4p9mwAoAPIm6OzuVZtn7idgEJeAJN3Q==", + "version": "14.2.27", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.27.tgz", + "integrity": "sha512-xmTsnu6rbXVaupRmU2k3BHVpQp7kK+/Ge9XYZlwXQNS2IPP/U9ToDoO6tTSzZIV36fmDBnwKqBUd7KuFXTi0Mw==", "license": "MIT", "dependencies": { - "@next/env": "14.2.25", + "@next/env": "14.2.27", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -12256,15 +12256,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.25", - "@next/swc-darwin-x64": "14.2.25", - "@next/swc-linux-arm64-gnu": "14.2.25", - "@next/swc-linux-arm64-musl": "14.2.25", - "@next/swc-linux-x64-gnu": "14.2.25", - "@next/swc-linux-x64-musl": "14.2.25", - "@next/swc-win32-arm64-msvc": "14.2.25", - "@next/swc-win32-ia32-msvc": "14.2.25", - "@next/swc-win32-x64-msvc": "14.2.25" + "@next/swc-darwin-arm64": "14.2.27", + "@next/swc-darwin-x64": "14.2.27", + "@next/swc-linux-arm64-gnu": "14.2.27", + "@next/swc-linux-arm64-musl": "14.2.27", + "@next/swc-linux-x64-gnu": "14.2.27", + "@next/swc-linux-x64-musl": "14.2.27", + "@next/swc-win32-arm64-msvc": "14.2.27", + "@next/swc-win32-ia32-msvc": "14.2.27", + "@next/swc-win32-x64-msvc": "14.2.27" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/ui/package.json b/ui/package.json index 4a08e910a9..25a1cdfb1a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -28,7 +28,7 @@ "jose": "^5.9.3", "jwt-decode": "^4.0.0", "lucide-react": "^0.471.0", - "next": "^14.2.25", + "next": "^14.2.26", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", "radix-ui": "^1.1.3", From 8fb10fbbf70401b7e4ec749022ff06d3edc9c7ce Mon Sep 17 00:00:00 2001 From: Drew Kerrigan Date: Tue, 8 Apr 2025 11:43:44 -0400 Subject: [PATCH 134/359] fix(ui): Remove UTC from timestamps in app (#7474) --- ui/components/ui/entities/date-with-time.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/ui/entities/date-with-time.tsx b/ui/components/ui/entities/date-with-time.tsx index 50e0efe8b5..e04c3e1cb6 100644 --- a/ui/components/ui/entities/date-with-time.tsx +++ b/ui/components/ui/entities/date-with-time.tsx @@ -23,7 +23,7 @@ export const DateWithTime: React.FC = ({ } const formattedDate = format(date, "MMM dd, yyyy"); - const formattedTime = format(date, "p 'UTC'"); + const formattedTime = format(date, "p"); return ( @@ -581,9 +627,14 @@ class HTML(Output):
  • M365 Identity ID: {provider.identity.identity_id}
  • - {f'''
  • + { + f'''
  • M365 User: {provider.identity.user} -
  • ''' if hasattr(provider.identity, 'user') and provider.identity.user is not None else ""} + ''' + if hasattr(provider.identity, "user") + and provider.identity.user is not None + else "" + }
    From 993ff4d78e71dc589220ae014d2771585b40a121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Tue, 8 Apr 2025 21:04:08 +0200 Subject: [PATCH 135/359] feat(gcp): add SOC2 compliance framework (#7476) --- README.md | 2 +- dashboard/compliance/soc2_gcp.py | 24 ++ prowler/compliance/aws/soc2_aws.json | 2 +- prowler/compliance/gcp/soc2_gcp.json | 496 +++++++++++++++++++++++++++ 4 files changed, 522 insertions(+), 2 deletions(-) create mode 100644 dashboard/compliance/soc2_gcp.py create mode 100644 prowler/compliance/gcp/soc2_gcp.json diff --git a/README.md b/README.md index 3f51786d0f..55d84b2d8d 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | |---|---|---|---|---| | AWS | 564 | 82 | 33 | 10 | -| GCP | 78 | 13 | 6 | 3 | +| GCP | 78 | 13 | 7 | 3 | | Azure | 140 | 18 | 7 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | | Microsoft365 | 5 | 2 | 1 | 0 | diff --git a/dashboard/compliance/soc2_gcp.py b/dashboard/compliance/soc2_gcp.py new file mode 100644 index 0000000000..2d5517aed6 --- /dev/null +++ b/dashboard/compliance/soc2_gcp.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_format3 + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_format3( + aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID" + ) diff --git a/prowler/compliance/aws/soc2_aws.json b/prowler/compliance/aws/soc2_aws.json index c5a38bd38e..0160111ef0 100644 --- a/prowler/compliance/aws/soc2_aws.json +++ b/prowler/compliance/aws/soc2_aws.json @@ -277,7 +277,7 @@ { "ItemId": "cc_6_7", "Section": "CC6.0 - Logical and Physical Access", - "Service": "acm", + "Service": "aws", "Type": "automated" } ], diff --git a/prowler/compliance/gcp/soc2_gcp.json b/prowler/compliance/gcp/soc2_gcp.json new file mode 100644 index 0000000000..55e9da8d11 --- /dev/null +++ b/prowler/compliance/gcp/soc2_gcp.json @@ -0,0 +1,496 @@ +{ + "Framework": "SOC2", + "Version": "", + "Provider": "GCP", + "Description": "System and Organization Controls (SOC), defined by the American Institute of Certified Public Accountants (AICPA), is the name of a set of reports that's produced during an audit. It's intended for use by service organizations (organizations that provide information systems as a service to other organizations) to issue validated reports of internal controls over those information systems to the users of those services. The reports focus on controls grouped into five categories known as Trust Service Principles.", + "Requirements": [ + { + "Id": "cc_1_3", + "Name": "CC1.3 COSO Principle 3: Management establishes, with board oversight, structures, reporting lines, and appropriate authorities and responsibilities in the pursuit of objectives", + "Description": "Considers All Structures of the Entity - Management and the board of directors consider the multiple structures used (including operating units, legal entities, geographic distribution, and outsourced service providers) to support the achievement of objectives. Establishes Reporting Lines - Management designs and evaluates lines of reporting for each entity structure to enable execution of authorities and responsibilities and flow of information to manage the activities of the entity. Defines, Assigns, and Limits Authorities and Responsibilities - Management and the board of directors delegate authority, define responsibilities, and use appropriate processes and technology to assign responsibility and segregate duties as necessary at the various levels of the organization. Additional points of focus specifically related to all engagements using the trust services criteria: Addresses Specific Requirements When Defining Authorities and Responsibilities—Management and the board of directors consider requirements relevant to security, availability, processing integrity, confidentiality, and privacy when defining authorities and responsibilities. Considers Interactions With External Parties When Establishing Structures, Reporting Lines, Authorities, and Responsibilities — Management and the board of directors consider the need for the entity to interact with and monitor the activities of external parties when establishing structures, reporting lines, authorities, and responsibilities.", + "Attributes": [ + { + "ItemId": "cc_1_3", + "Section": "CC1.0 - Common Criteria Related to Control Environment", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_account_access_approval_enabled", + "iam_cloud_asset_inventory_enabled", + "iam_no_service_roles_at_project_level", + "iam_organization_essential_contacts_configured", + "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_unused" + ] + }, + { + "Id": "cc_2_1", + "Name": "CC2.1 COSO Principle 13: The entity obtains or generates and uses relevant, quality information to support the functioning of internal control", + "Description": "Identifies Information Requirements - A process is in place to identify the information required and expected to support the functioning of the other components of internal control and the achievement of the entity’s objectives. Captures Internal and External Sources of Data - Information systems capture internal and external sources of data. Processes Relevant Data Into Information - Information systems process and transform relevant data into information. Maintains Quality Throughout Processing - Information systems produce information that is timely, current, accurate, complete, accessible, protected, verifiable, and retained. Information is reviewed to assess its relevance in supporting the internal control components.", + "Attributes": [ + { + "ItemId": "cc_2_1", + "Section": "CC2.0 - Common Criteria Related to Communication and Information", + "Service": "logging", + "Type": "automated" + } + ], + "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_project_ownership_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" + ] + }, + { + "Id": "cc_3_1", + "Name": "CC3.1 COSO Principle 6: The entity specifies objectives with sufficient clarity to enable the identification and assessment of risks relating to objectives", + "Description": "Operations Objectives: Reflects Management's Choices - Operations objectives reflect management's choices about structure, industry considerations, and performance of the entity. Considers Tolerances for Risk - Management considers the acceptable levels of variation relative to the achievement of operations objectives. External Financial Reporting Objectives: Complies With Applicable Accounting Standards - Financial reporting objectives are consistent with accounting principles suitable and available for that entity. The accounting principles selected are appropriate in the circumstances. External Nonfinancial Reporting Objectives: Complies With Externally Established Frameworks - Management establishes objectives consistent with lgcp and regulations or standards and frameworks of recognized external organizations. Reflects Entity Activities - External reporting reflects the underlying transactions and events within a range of acceptable limits. Considers the Required Level of Precision—Management reflects the required level of precision and accuracy suitable for user needs and based on criteria established by third parties in nonfinancial reporting. Internal Reporting Objectives: Reflects Management's Choices - Internal reporting provides management with accurate and complete information regarding management's choices and information needed in managing the entity. Considers the Required Level of Precision—Management reflects the required level of precision and accuracy suitable for user needs in nonfinancial reporting objectives and materiality within financial reporting objectives. Reflects Entity Activities—Internal reporting reflects the underlying transactions and events within a range of acceptable limits. Compliance Objectives: Reflects External Lgcp and Regulations - Lgcp and regulations establish minimum standards of conduct, which the entity integrates into compliance objectives. Considers Tolerances for Risk - Management considers the acceptable levels of variation relative to the achievement of operations objectives. Additional point of focus specifically related to all engagements using the trust services criteria: Establishes Sub-objectives to Support Objectives—Management identifies sub-objectives related to security, availability, processing integrity, confidentiality, and privacy to support the achievement of the entity’s objectives related to reporting, operations, and compliance.", + "Attributes": [ + { + "ItemId": "cc_3_1", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "gcr_container_scanning_enabled", + "artifacts_container_analysis_enabled" + ] + }, + { + "Id": "cc_3_2", + "Name": "CC3.2 COSO Principle 7: The entity identifies risks to the achievement of its objectives across the entity and analyzes risks as a basis for determining how the risks should be managed", + "Description": "Includes Entity, Subsidiary, Division, Operating Unit, and Functional Levels - The entity identifies and assesses risk at the entity, subsidiary, division, operating unit, and functional levels relevant to the achievement of objectives. Analyzes Internal and External Factors - Risk identification considers both internal and external factors and their impact on the achievement of objectives. Involves Appropriate Levels of Management - The entity puts into place effective risk assessment mechanisms that involve appropriate levels of management. Estimates Significance of Risks Identified - Identified risks are analyzed through a process that includes estimating the potential significance of the risk. Determines How to Respond to Risks - Risk assessment includes considering how the risk should be managed and whether to accept, avoid, reduce, or share the risk. Additional points of focus specifically related to all engagements using the trust services criteria: Identifies and Assesses Criticality of Information Assets and Identifies Threats and Vulnerabilities - The entity's risk identification and assessment process includes (1) identifying information assets, including physical devices and systems, virtual devices, software, data and data flows, external information systems, and organizational roles; (2) assessing the criticality of those information assets; (3) identifying the threats to the assets from intentional (including malicious) and unintentional acts and environmental events; and (4) identifying the vulnerabilities of the identified assets.", + "Attributes": [ + { + "ItemId": "cc_3_2", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "gcr", + "Type": "automated" + } + ], + "Checks": [ + "gcr_container_scanning_enabled" + ] + }, + { + "Id": "cc_3_3", + "Name": "CC3.3 COSO Principle 8: The entity considers the potential for fraud in assessing risks to the achievement of objectives", + "Description": "Considers Various Types of Fraud - The assessment of fraud considers fraudulent reporting, possible loss of assets, and corruption resulting from the various ways that fraud and misconduct can occur. Assesses Incentives and Pressures - The assessment of fraud risks considers incentives and pressures. Assesses Opportunities - The assessment of fraud risk considers opportunities for unauthorized acquisition,use, or disposal of assets, altering the entity’s reporting records, or committing other inappropriate acts. Assesses Attitudes and Rationalizations - The assessment of fraud risk considers how management and other personnel might engage in or justify inappropriate actions. Additional point of focus specifically related to all engagements using the trust services criteria: Considers the Risks Related to the Use of IT and Access to Information - The assessment of fraud risks includes consideration of threats and vulnerabilities that arise specifically from the use of IT and access to information.", + "Attributes": [ + { + "ItemId": "cc_3_3", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "logging", + "Type": "automated" + } + ], + "Checks": [ + "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_bucket_permission_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": "cc_3_4", + "Name": "CC3.4 COSO Principle 9: The entity identifies and assesses changes that could significantly impact the system of internal control", + "Description": "Assesses Changes in the External Environment - The risk identification process considers changes to the regulatory, economic, and physical environment in which the entity operates. Assesses Changes in the Business Model - The entity considers the potential impacts of new business lines, dramatically altered compositions of existing business lines, acquired or divested business operations on the system of internal control, rapid growth, changing reliance on foreign geographies, and new technologies. Assesses Changes in Leadership - The entity considers changes in management and respective attitudes and philosophies on the system of internal control. Assess Changes in Systems and Technology - The risk identification process considers changes arising from changes in the entity’s systems and changes in the technology environment. Assess Changes in Vendor and Business Partner Relationships - The risk identification process considers changes in vendor and business partner relationships.", + "Attributes": [ + { + "ItemId": "cc_3_4", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_4_2", + "Name": "CC4.2 COSO Principle 17: The entity evaluates and communicates internal control deficiencies in a timely manner to those parties responsible for taking corrective action, including senior management and the board of directors, as appropriate", + "Description": "Assesses Results - Management and the board of directors, as appropriate, assess results of ongoing and separate evaluations. Communicates Deficiencies - Deficiencies are communicated to parties responsible for taking corrective action and to senior management and the board of directors, as appropriate. Monitors Corrective Action - Management tracks whether deficiencies are remedied on a timely basis.", + "Attributes": [ + { + "ItemId": "cc_4_2", + "Section": "CC4.0 - Monitoring Activities", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_5_2", + "Name": "CC5.2 COSO Principle 11: The entity also selects and develops general control activities over technology to support the achievement of objectives", + "Description": "Determines Dependency Between the Use of Technology in Business Processes and Technology General Controls - Management understands and determines the dependency and linkage between business processes, automated control activities, and technology general controls. Establishes Relevant Technology Infrastructure Control Activities - Management selects and develops control activities over the technology infrastructure, which are designed and implemented to help ensure the completeness, accuracy, and availability of technology processing. Establishes Relevant Security Management Process Controls Activities - Management selects and develops control activities that are designed and implemented to restrict technology access rights to authorized users commensurate with their job responsibilities and to protect the entity’s assets from external threats. Establishes Relevant Technology Acquisition, Development, and Maintenance Process Control Activities - Management selects and develops control activities over the acquisition, development, and maintenance of technology and its infrastructure to achieve management’s objectives.", + "Attributes": [ + { + "ItemId": "cc_5_2", + "Section": "CC5.0 - Control Activities", + "Service": "logging", + "Type": "automated" + } + ], + "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_project_ownership_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" + ] + }, + { + "Id": "cc_6_1", + "Name": "CC6.1 The entity implements logical access security software, infrastructure, and architectures over protected information assets to protect them from security events to meet the entity's objectives", + "Description": "Identifies and Manages the Inventory of Information Assets - The entity identifies, inventories, classifies, and manages information assets. Restricts Logical Access - Logical access to information assets, including hardware, data (at-rest, during processing, or in transmission), software, administrative authorities, mobile devices, output, and offline system components is restricted through the use of access control software and rule sets. Identifies and Authenticates Users - Persons, infrastructure and software are identified and authenticated prior to accessing information assets, whether locally or remotely. Considers Network Segmentation - Network segmentation permits unrelated portions of the entity's information system to be isolated from each other. Manages Points of Access - Points of access by outside entities and the types of data that flow through the points of access are identified, inventoried, and managed. The types of individuals and systems using each point of access are identified, documented, and managed. Restricts Access to Information Assets - Combinations of data classification, separate data structures, port restrictions, access protocol restrictions, user identification, and digital certificates are used to establish access control rules for information assets. Manages Identification and Authentication - Identification and authentication requirements are established, documented, and managed for individuals and systems accessing entity information, infrastructure and software. Manages Credentials for Infrastructure and Software - New internal and external infrastructure and software are registered, authorized, and documented prior to being granted access credentials and implemented on the network or access point. Credentials are removed and access is disabled when access is no longer required or the infrastructure and software are no longer in use. Uses Encryption to Protect Data - The entity uses encryption to supplement other measures used to protect data-at-rest, when such protections are deemed appropriate based on assessed risk. Protects Encryption Keys - Processes are in place to protect encryption keys during generation, storage, use, and destruction.", + "Attributes": [ + { + "ItemId": "cc_6_1", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "cloudstorage", + "Type": "automated" + } + ], + "Checks": [ + "cloudstorage_bucket_public_access" + ] + }, + { + "Id": "cc_6_2", + "Name": "CC6.2 Prior to issuing system credentials and granting system access, the entity registers and authorizes new internal and external users whose access is administered by the entity", + "Description": "Prior to issuing system credentials and granting system access, the entity registers and authorizes new internal and external users whose access is administered by the entity. For those users whose access is administered by the entity, user system credentials are removed when user access is no longer authorized. Controls Access Credentials to Protected Assets - Information asset access credentials are created based on an authorization from the system's asset owner or authorized custodian. Removes Access to Protected Assets When Appropriate - Processes are in place to remove credential access when an individual no longer requires such access. Reviews Appropriateness of Access Credentials - The appropriateness of access credentials is reviewed on a periodic basis for unnecessary and inappropriate individuals with credentials.", + "Attributes": [ + { + "ItemId": "cc_6_2", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "cloudsql", + "Type": "automated" + } + ], + "Checks": [ + "cloudsql_instance_public_access" + ] + }, + { + "Id": "cc_6_3", + "Name": "CC6.3 The entity authorizes, modifies, or removes access to data, software, functions, and other protected information assets based on roles, responsibilities, or the system design and changes, giving consideration to the concepts of least privilege and segregation of duties, to meet the entity’s objectives", + "Description": "Creates or Modifies Access to Protected Information Assets - Processes are in place to create or modify access to protected information assets based on authorization from the asset’s owner. Removes Access to Protected Information Assets - Processes are in place to remove access to protected information assets when an individual no longer requires access. Uses Role-Based Access Controls - Role-based access control is utilized to support segregation of incompatible functions.", + "Attributes": [ + { + "ItemId": "cc_6_3", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_account_access_approval_enabled", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_sa_no_administrative_privileges", + "iam_sa_user_managed_key_unused" + ] + }, + { + "Id": "cc_6_6", + "Name": "CC6.6 The entity implements logical access security measures to protect against threats from sources outside its system boundaries", + "Description": "Restricts Access — The types of activities that can occur through a communication channel (for example, FTP site, router port) are restricted. Protects Identification and Authentication Credentials — Identification and authentication credentials are protected during transmission outside its system boundaries. Requires Additional Authentication or Credentials — Additional authentication information or credentials are required when accessing the system from outside its boundaries. Implements Boundary Protection Systems — Boundary protection systems (for example, firewalls, demilitarized zones, and intrusion detection systems) are implemented to protect external access points from attempts and unauthorized access and are monitored to detect such attempts.", + "Attributes": [ + { + "ItemId": "cc_6_6", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "compute", + "Type": "automated" + } + ], + "Checks": [ + "compute_firewall_rdp_access_from_the_internet_allowed", + "compute_firewall_ssh_access_from_the_internet_allowed", + "compute_instance_block_project_wide_ssh_keys_disabled", + "compute_instance_ip_forwarding_is_enabled", + "compute_instance_public_ip", + "compute_instance_serial_ports_in_use", + "compute_network_dns_logging_enabled", + "compute_public_address_shodan" + ] + }, + { + "Id": "cc_6_7", + "Name": "CC6.7 The entity restricts the transmission, movement, and removal of information to authorized internal and external users and processes, and protects it during transmission, movement, or removal to meet the entity’s objectives", + "Description": "Restricts the Ability to Perform Transmission - Data loss prevention processes and technologies are used to restrict ability to authorize and execute transmission, movement and removal of information. Uses Encryption Technologies or Secure Communication Channels to Protect Data - Encryption technologies or secured communication channels are used to protect transmission of data and other communications beyond connectivity access points. Protects Removal Media - Encryption technologies and physical asset protections are used for removable media (such as USB drives and back-up tapes), as appropriate. Protects Mobile Devices - Processes are in place to protect mobile devices (such as laptops, smart phones and tablets) that serve as information assets.", + "Attributes": [ + { + "ItemId": "cc_6_7", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "dns_dnssec_disabled", + "dns_rsasha1_in_use_to_key_sign_in_dnssec", + "dns_rsasha1_in_use_to_zone_sign_in_dnssec", + "compute_firewall_rdp_access_from_the_internet_allowed", + "compute_firewall_ssh_access_from_the_internet_allowed", + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "cc_6_8", + "Name": "CC6.8 The entity implements controls to prevent or detect and act upon the introduction of unauthorized or malicious software to meet the entity’s objectives", + "Description": "Restricts Application and Software Installation - The ability to install applications and software is restricted to authorized individuals. Detects Unauthorized Changes to Software and Configuration Parameters - Processes are in place to detect changes to software and configuration parameters that may be indicative of unauthorized or malicious software. Uses a Defined Change Control Process - A management-defined change control process is used for the implementation of software. Uses Antivirus and Anti-Malware Software - Antivirus and anti-malware software is implemented and maintained to provide for the interception or detection and remediation of malware. Scans Information Assets from Outside the Entity for Malware and Other Unauthorized Software - Procedures are in place to scan information assets that have been transferred or returned to the entity’s custody for malware and other unauthorized software and to remove any items detected prior to its implementation on the network.", + "Attributes": [ + { + "ItemId": "cc_6_8", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_7_1", + "Name": "CC7.1 To meet its objectives, the entity uses detection and monitoring procedures to identify (1) changes to configurations that result in the introduction of new vulnerabilities, and (2) susceptibilities to newly discovered vulnerabilities", + "Description": "Uses Defined Configuration Standards - Management has defined configuration standards. Monitors Infrastructure and Software - The entity monitors infrastructure and software for noncompliance with the standards, which could threaten the achievement of the entity's objectives. Implements Change-Detection Mechanisms - The IT system includes a change-detection mechanism (for example, file integrity monitoring tools) to alert personnel to unauthorized modifications of critical system files, configuration files, or content files. Detects Unknown or Unauthorized Components - Procedures are in place to detect the introduction of unknown or unauthorized components. Conducts Vulnerability Scans - The entity conducts vulnerability scans designed to identify potential vulnerabilities or misconfigurations on a periodic basis and after any significant change in the environment and takes action to remediate identified deficiencies on a timely basis.", + "Attributes": [ + { + "ItemId": "cc_7_1", + "Section": "CC7.0 - System Operations", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_7_2", + "Name": "CC7.2 The entity monitors system components and the operation of those components for anomalies that are indicative of malicious acts, natural disasters, and errors affecting the entity's ability to meet its objectives; anomalies are analyzed to determine whether they represent security events", + "Description": "Implements Detection Policies, Procedures, and Tools - Detection policies and procedures are defined and implemented, and detection tools are implemented on Infrastructure and software to identify anomalies in the operation or unusual activity on systems. Procedures may include (1) a defined governance process for security event detection and management that includes provision of resources; (2) use of intelligence sources to identify newly discovered threats and vulnerabilities; and (3) logging of unusual system activities. Designs Detection Measures - Detection measures are designed to identify anomalies that could result from actual or attempted (1) compromise of physical barriers; (2) unauthorized actions of authorized personnel; (3) use of compromised identification and authentication credentials; (4) unauthorized access from outside the system boundaries; (5) compromise of authorized external parties; and (6) implementation or connection of unauthorized hardware and software. Implements Filters to Analyze Anomalies - Management has implemented procedures to filter, summarize, and analyze anomalies to identify security events. Monitors Detection Tools for Effective Operation - Management has implemented processes to monitor the effectiveness of detection tools.", + "Attributes": [ + { + "ItemId": "cc_7_2", + "Section": "CC7.0 - System Operations", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "cloudsql_instance_postgres_log_connections_flag", + "cloudsql_instance_postgres_log_disconnections_flag", + "cloudsql_instance_postgres_log_error_verbosity_flag", + "cloudsql_instance_postgres_log_min_duration_statement_flag", + "cloudsql_instance_postgres_log_min_error_statement_flag", + "cloudsql_instance_postgres_log_min_messages_flag", + "cloudsql_instance_postgres_log_statement_flag", + "cloudstorage_bucket_log_retention_policy_lock", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_enabled", + "compute_project_os_login_enabled", + "compute_subnet_flow_logs_enabled", + "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_project_ownership_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" + ] + }, + { + "Id": "cc_7_3", + "Name": "CC7.3 The entity evaluates security events to determine whether they could or have resulted in a failure of the entity to meet its objectives (security incidents) and, if so, takes actions to prevent or address such failures", + "Description": "Responds to Security Incidents - Procedures are in place for responding to security incidents and evaluating the effectiveness of those policies and procedures on a periodic basis. Communicates and Reviews Detected Security Events - Detected security events are communicated to and reviewed by the individuals responsible for the management of the security program and actions are taken, if necessary. Develops and Implements Procedures to Analyze Security Incidents - Procedures are in place to analyze security incidents and determine system impact. Assesses the Impact on Personal Information - Detected security events are evaluated to determine whether they could or did result in the unauthorized disclosure or use of personal information and whether there has been a failure to comply with applicable lgcp or regulations. Determines Personal Information Used or Disclosed - When an unauthorized use or disclosure of personal information has occurred, the affected information is identified.", + "Attributes": [ + { + "ItemId": "cc_7_3", + "Section": "CC7.0 - System Operations", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "cloudsql_instance_postgres_log_connections_flag", + "cloudsql_instance_postgres_log_disconnections_flag", + "cloudsql_instance_postgres_log_error_verbosity_flag", + "cloudsql_instance_postgres_log_min_duration_statement_flag", + "cloudsql_instance_postgres_log_min_error_statement_flag", + "cloudsql_instance_postgres_log_min_messages_flag", + "cloudsql_instance_postgres_log_statement_flag", + "cloudstorage_bucket_log_retention_policy_lock", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_enabled", + "compute_project_os_login_enabled", + "compute_subnet_flow_logs_enabled", + "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_project_ownership_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_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_7_4", + "Name": "CC7.4 The entity responds to identified security incidents by executing a defined incident response program to understand, contain, remediate, and communicate security incidents, as appropriate", + "Description": "Assigns Roles and Responsibilities - Roles and responsibilities for the design, implementation, maintenance, and execution of the incident response program are assigned, including the use of external resources when necessary. Contains Security Incidents - Procedures are in place to contain security incidents that actively threaten entity objectives. Mitigates Ongoing Security Incidents - Procedures are in place to mitigate the effects of ongoing security incidents. Ends Threats Posed by Security Incidents - Procedures are in place to end the threats posed by security incidents through closure of the vulnerability, removal of unauthorized access, and other remediation actions. Restores Operations - Procedures are in place to restore data and business operations to an interim state that permits the achievement of entity objectives. Develops and Implements Communication Protocols for Security Incidents - Protocols for communicating security incidents and actions taken to affected parties are developed and implemented to meet the entity's objectives. Obtains Understanding of Nature of Incident and Determines Containment Strategy - An understanding of the nature (for example, the method by which the incident occurred and the affected system resources) and severity of the security incident is obtained to determine the appropriate containment strategy, including (1) a determination of the appropriate response time frame, and (2) the determination and execution of the containment approach. Remediates Identified Vulnerabilities - Identified vulnerabilities are remediated through the development and execution of remediation activities. Communicates Remediation Activities - Remediation activities are documented and communicated in accordance with the incident response program. Evaluates the Effectiveness of Incident Response - The design of incident response activities is evaluated for effectiveness on a periodic basis. Periodically Evaluates Incidents - Periodically, management reviews incidents related to security, availability, processing integrity, confidentiality, and privacy and identifies the need for system changes based on incident patterns and root causes. Communicates Unauthorized Use and Disclosure - Events that resulted in unauthorized use or disclosure of personal information are communicated to the data subjects, legal and regulatory authorities, and others as required. Application of Sanctions - The conduct of individuals and organizations operating under the authority of the entity and involved in the unauthorized use or disclosure of personal information is evaluated and, if appropriate, sanctioned in accordance with entity policies and legal and regulatory requirements.", + "Attributes": [ + { + "ItemId": "cc_7_4", + "Section": "CC7.0 - System Operations", + "Service": "gcp", + "Type": "automated" + } + ], + "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_project_ownership_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", + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "cc_7_5", + "Name": "CC7.5 The entity identifies, develops, and implements activities to recover from identified security incidents", + "Description": "Restores the Affected Environment - The activities restore the affected environment to functional operation by rebuilding systems, updating software, installing patches, and changing configurations, as needed. Communicates Information About the Event - Communications about the nature of the incident, recovery actions taken, and activities required for the prevention of future security events are made to management and others as appropriate (internal and external). Determines Root Cause of the Event - The root cause of the event is determined. Implements Changes to Prevent and Detect Recurrences - Additional architecture or changes to preventive and detective controls, or both, are implemented to prevent and detect recurrences on a timely basis. Improves Response and Recovery Procedures - Lessons learned are analyzed, and the incident response plan and recovery procedures are improved. Implements Incident Recovery Plan Testing - Incident recovery plan testing is performed on a periodic basis. The testing includes (1) development of testing scenarios based on threat likelihood and magnitude; (2) consideration of relevant system components from across the entity that can impair availability; (3) scenarios that consider the potential for the lack of availability of key personnel; and (4) revision of continuity plans and systems based on test results.", + "Attributes": [ + { + "ItemId": "cc_7_5", + "Section": "CC7.0 - System Operations", + "Service": "cloudsql", + "Type": "automated" + } + ], + "Checks": [ + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "cc_8_1", + "Name": "CC8.1 The entity authorizes, designs, develops or acquires, configures, documents, tests, approves, and implements changes to infrastructure, data, software, and procedures to meet its objectives", + "Description": "Manages Changes Throughout the System Lifecycle - A process for managing system changes throughout the lifecycle of the system and its components (infrastructure, data, software and procedures) is used to support system availability and processing integrity. Authorizes Changes - A process is in place to authorize system changes prior to development. Designs and Develops Changes - A process is in place to design and develop system changes. Documents Changes - A process is in place to document system changes to support ongoing maintenance of the system and to support system users in performing their responsibilities. Tracks System Changes - A process is in place to track system changes prior to implementation. Configures Software - A process is in place to select and implement the configuration parameters used to control the functionality of software. Tests System Changes - A process is in place to test system changes prior to implementation. Approves System Changes - A process is in place to approve system changes prior to implementation. Deploys System Changes - A process is in place to implement system changes. Identifies and Evaluates System Changes - Objectives affected by system changes are identified, and the ability of the modified system to meet the objectives is evaluated throughout the system development life cycle. Identifies Changes in Infrastructure, Data, Software, and Procedures Required to Remediate Incidents - Changes in infrastructure, data, software, and procedures required to remediate incidents to continue to meet objectives are identified, and the change process is initiated upon identification. Creates Baseline Configuration of IT Technology - A baseline configuration of IT and control systems is created and maintained. Provides for Changes Necessary in Emergency Situations - A process is in place for authorizing, designing, testing, approving and implementing changes necessary in emergency situations (that is, changes that need to be implemented in an urgent timeframe). Protects Confidential Information - The entity protects confidential information during system design, development, testing, implementation, and change processes to meet the entity’s objectives related to confidentiality. Protects Personal Information - The entity protects personal information during system design, development, testing, implementation, and change processes to meet the entity’s objectives related to privacy.", + "Attributes": [ + { + "ItemId": "cc_8_1", + "Section": "CC8.0 - Change Management", + "Service": "iam", + "Type": "automated" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "cc_a_1_1", + "Name": "A1.2 The entity authorizes, designs, develops or acquires, implements, operates, approves, maintains, and monitors environmental protections, software, data back-up processes, and recovery infrastructure to meet its objectives", + "Description": "Measures Current Usage - The use of the system components is measured to establish a baseline for capacity management and to use when evaluating the risk of impaired availability due to capacity constraints. Forecasts Capacity - The expected average and peak use of system components is forecasted and compared to system capacity and associated tolerances. Forecasting considers capacity in the event of the failure of system components that constrain capacity. Makes Changes Based on Forecasts - The system change management process is initiated when forecasted usage exceeds capacity tolerances.", + "Attributes": [ + { + "ItemId": "cc_a_1_1", + "Section": "CCA1.0 - Additional Criterial for Availability", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "cloudsql_instance_postgres_log_connections_flag", + "cloudsql_instance_postgres_log_disconnections_flag", + "cloudsql_instance_postgres_log_error_verbosity_flag", + "cloudsql_instance_postgres_log_min_duration_statement_flag", + "cloudsql_instance_postgres_log_min_error_statement_flag", + "cloudsql_instance_postgres_log_min_messages_flag", + "cloudsql_instance_postgres_log_statement_flag", + "cloudstorage_bucket_log_retention_policy_lock", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_enabled", + "compute_project_os_login_enabled", + "compute_subnet_flow_logs_enabled", + "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_project_ownership_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" + ] + }, + { + "Id": "cc_c_1_1", + "Name": "C1.1 The entity identifies and maintains confidential information to meet the entity’s objectives related to confidentiality", + "Description": "Identifies Confidential information - Procedures are in place to identify and designate confidential information when it is received or created and to determine the period over which the confidential information is to be retained. Protects Confidential Information from Destruction - Procedures are in place to protect confidential information from erasure or destruction during the specified retention period of the information", + "Attributes": [ + { + "ItemId": "cc_c_1_1", + "Section": "CCC1.0 - Additional Criterial for Confidentiality", + "Service": "gcp", + "Type": "automated" + } + ], + "Checks": [ + "compute_instance_confidential_computing_enabled", + "bigquery_table_cmk_encryption", + "bigquery_dataset_cmk_encryption", + "compute_instance_encryption_with_csek_enabled", + "dataproc_encrypted_with_cmks_disabled" + ] + }, + { + "Id": "cc_c_1_2", + "Name": "C1.2 The entity disposes of confidential information to meet the entity’s objectives related to confidentiality", + "Description": "Identifies Confidential Information for Destruction - Procedures are in place to identify confidential information requiring destruction when the end of the retention period is reached. Destroys Confidential Information - Procedures are in place to erase or otherwise destroy confidential information that has been identified for destruction.", + "Attributes": [ + { + "ItemId": "cc_c_1_2", + "Section": "CCC1.0 - Additional Criterial for Confidentiality", + "Service": "cloudstorage", + "Type": "automated" + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ] + } + ] +} From 53cb57901f20c70104a710d25d95d8083aef8451 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 9 Apr 2025 13:44:53 +0200 Subject: [PATCH 136/359] fix: fix TS type for session duration (#7481) --- ui/types/formSchemas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts index e23d47eb55..b39a7d92a4 100644 --- a/ui/types/formSchemas.ts +++ b/ui/types/formSchemas.ts @@ -142,7 +142,7 @@ export const addCredentialsRoleFormSchema = (providerType: string) => aws_access_key_id: z.string().optional(), aws_secret_access_key: z.string().optional(), aws_session_token: z.string().optional(), - session_duration: z.number().optional(), + session_duration: z.string().optional(), role_session_name: z.string().optional(), credentials_type: z.string().optional(), }) From 61000e386bf6b361ed8319f2567d24551059a21e Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Wed, 9 Apr 2025 15:11:29 +0200 Subject: [PATCH 137/359] chore(regions_update): Changes in regions for AWS services (#7478) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 5bcf316f5c..4a3b4bac59 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -4155,6 +4155,7 @@ "ap-southeast-2", "ap-southeast-3", "ca-central-1", + "ca-west-1", "eu-central-1", "eu-north-1", "eu-south-1", @@ -7919,6 +7920,7 @@ "ca-central-1", "eu-central-1", "eu-north-1", + "eu-south-2", "eu-west-1", "eu-west-2", "sa-east-1", From 3ef79588b4844f39f9dbce6cf8da4d5d5bcb070f Mon Sep 17 00:00:00 2001 From: eeche Date: Wed, 9 Apr 2025 22:13:24 +0900 Subject: [PATCH 138/359] feat(NHN): add NHN cloud provider with 6 checks (#6870) Co-authored-by: MrCloudSec --- README.md | 1 + prowler/__main__.py | 35 + prowler/compliance/nhn/__init__.py | 0 prowler/compliance/nhn/iso27001_2022_nhn.json | 1313 +++++++++++++++++ prowler/config/config.py | 1 + prowler/lib/check/models.py | 23 + prowler/lib/cli/parser.py | 5 +- .../compliance/iso27001/iso27001_nhn.py | 87 ++ .../lib/outputs/compliance/iso27001/models.py | 25 + prowler/lib/outputs/finding.py | 15 + prowler/lib/outputs/html/html.py | 45 + prowler/lib/outputs/outputs.py | 2 + prowler/lib/outputs/summary_table.py | 3 + prowler/providers/common/provider.py | 9 + prowler/providers/nhn/__init__.py | 0 .../providers/nhn/exceptions/exceptions.py | 0 prowler/providers/nhn/lib/__init__.py | 0 .../providers/nhn/lib/arguments/__init__.py | 0 .../providers/nhn/lib/arguments/arguments.py | 17 + .../providers/nhn/lib/mutelist/__init__.py | 0 .../providers/nhn/lib/mutelist/mutelist.py | 14 + prowler/providers/nhn/lib/service/__init__.py | 0 prowler/providers/nhn/lib/service/service.py | 1 + prowler/providers/nhn/models.py | 56 + prowler/providers/nhn/nhn_provider.py | 308 ++++ .../nhn/services/compute/__init__.py | 0 .../nhn/services/compute/compute_client.py | 4 + .../compute_instance_login_user/__init__.py | 0 .../compute_instance_login_user.metadata.json | 30 + .../compute_instance_login_user.py | 22 + .../compute_instance_public_ip/__init__.py | 0 .../compute_instance_public_ip.metadata.json | 30 + .../compute_instance_public_ip.py | 22 + .../__init__.py | 0 ...ute_instance_security_groups.metadata.json | 30 + .../compute_instance_security_groups.py | 24 + .../nhn/services/compute/compute_service.py | 95 ++ .../nhn/services/network/__init__.py | 0 .../nhn/services/network/network_client.py | 4 + .../nhn/services/network/network_service.py | 89 ++ .../__init__.py | 0 ..._vpc_has_empty_routingtables.metadata.json | 30 + .../network_vpc_has_empty_routingtables.py | 22 + .../__init__.py | 0 ...twork_vpc_subnet_enable_dhcp.metadata.json | 30 + .../network_vpc_subnet_enable_dhcp.py | 23 + .../__init__.py | 0 ...c_subnet_has_external_router.metadata.json | 30 + .../network_vpc_subnet_has_external_router.py | 21 + tests/lib/cli/parser_test.py | 4 +- .../lib/mutelist/fixtures/nhn_mutelist.yaml | 16 + .../nhn/lib/mutelist/nhn_mutelist_test.py | 100 ++ tests/providers/nhn/nhn_fixtures.py | 29 + tests/providers/nhn/nhn_provider_test.py | 157 ++ ...ompute_instance_login_user_test_for_nhn.py | 110 ++ ...compute_instance_public_ip_test_for_nhn.py | 107 ++ ...e_instance_security_groups_test_for_nhn.py | 108 ++ .../compute/compute_service_test_for_nhn.py | 100 ++ .../network/network_service_test_for_nhn.py | 98 ++ ...pc_has_empty_routingtables_test_for_nhn.py | 107 ++ .../network_vpc_subnet_enable_dhcp_for_nhn.py | 113 ++ ..._vpc_subnet_has_external_router_for_nhn.py | 104 ++ 62 files changed, 3615 insertions(+), 4 deletions(-) create mode 100644 prowler/compliance/nhn/__init__.py create mode 100644 prowler/compliance/nhn/iso27001_2022_nhn.json create mode 100644 prowler/lib/outputs/compliance/iso27001/iso27001_nhn.py create mode 100644 prowler/providers/nhn/__init__.py create mode 100644 prowler/providers/nhn/exceptions/exceptions.py create mode 100644 prowler/providers/nhn/lib/__init__.py create mode 100644 prowler/providers/nhn/lib/arguments/__init__.py create mode 100644 prowler/providers/nhn/lib/arguments/arguments.py create mode 100644 prowler/providers/nhn/lib/mutelist/__init__.py create mode 100644 prowler/providers/nhn/lib/mutelist/mutelist.py create mode 100644 prowler/providers/nhn/lib/service/__init__.py create mode 100644 prowler/providers/nhn/lib/service/service.py create mode 100644 prowler/providers/nhn/models.py create mode 100644 prowler/providers/nhn/nhn_provider.py create mode 100644 prowler/providers/nhn/services/compute/__init__.py create mode 100644 prowler/providers/nhn/services/compute/compute_client.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_login_user/__init__.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.metadata.json create mode 100644 prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_public_ip/__init__.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.metadata.json create mode 100644 prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_security_groups/__init__.py create mode 100644 prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.metadata.json create mode 100644 prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.py create mode 100644 prowler/providers/nhn/services/compute/compute_service.py create mode 100644 prowler/providers/nhn/services/network/__init__.py create mode 100644 prowler/providers/nhn/services/network/network_client.py create mode 100644 prowler/providers/nhn/services/network/network_service.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/__init__.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.metadata.json create mode 100644 prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/__init__.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.metadata.json create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/__init__.py create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.metadata.json create mode 100644 prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.py create mode 100644 tests/providers/nhn/lib/mutelist/fixtures/nhn_mutelist.yaml create mode 100644 tests/providers/nhn/lib/mutelist/nhn_mutelist_test.py create mode 100644 tests/providers/nhn/nhn_fixtures.py create mode 100644 tests/providers/nhn/nhn_provider_test.py create mode 100644 tests/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user_test_for_nhn.py create mode 100644 tests/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip_test_for_nhn.py create mode 100644 tests/providers/nhn/services/compute/compute_instance_security__groups/compute_instance_security_groups_test_for_nhn.py create mode 100644 tests/providers/nhn/services/compute/compute_service_test_for_nhn.py create mode 100644 tests/providers/nhn/services/network/network_service_test_for_nhn.py create mode 100644 tests/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables_test_for_nhn.py create mode 100644 tests/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp_for_nhn.py create mode 100644 tests/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router_for_nhn.py diff --git a/README.md b/README.md index 55d84b2d8d..f7592cdf98 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | Azure | 140 | 18 | 7 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | | Microsoft365 | 5 | 2 | 1 | 0 | +| NHN (Unofficial) | 6 | 2 | 1 | 0 | > You can list the checks, services, compliance frameworks and categories with `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`. diff --git a/prowler/__main__.py b/prowler/__main__.py index d27b7da8e9..f7e617ebcc 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -63,6 +63,7 @@ from prowler.lib.outputs.compliance.iso27001.iso27001_gcp import GCPISO27001 from prowler.lib.outputs.compliance.iso27001.iso27001_kubernetes import ( KubernetesISO27001, ) +from prowler.lib.outputs.compliance.iso27001.iso27001_nhn import NHNISO27001 from prowler.lib.outputs.compliance.kisa_ismsp.kisa_ismsp_aws import AWSKISAISMSP from prowler.lib.outputs.compliance.mitre_attack.mitre_attack_aws import AWSMitreAttack from prowler.lib.outputs.compliance.mitre_attack.mitre_attack_azure import ( @@ -85,6 +86,7 @@ from prowler.providers.common.quick_inventory import run_provider_quick_inventor from prowler.providers.gcp.models import GCPOutputOptions from prowler.providers.kubernetes.models import KubernetesOutputOptions from prowler.providers.microsoft365.models import Microsoft365OutputOptions +from prowler.providers.nhn.models import NHNOutputOptions def prowler(): @@ -270,6 +272,10 @@ def prowler(): output_options = Microsoft365OutputOptions( args, bulk_checks_metadata, global_provider.identity ) + elif provider == "nhn": + output_options = NHNOutputOptions( + args, bulk_checks_metadata, global_provider.identity + ) # Run the quick inventory for the provider if available if hasattr(args, "quick_inventory") and args.quick_inventory: @@ -688,6 +694,35 @@ def prowler(): generated_outputs["compliance"].append(generic_compliance) generic_compliance.batch_write_data_to_file() + elif provider == "nhn": + for compliance_name in input_compliance_frameworks: + if compliance_name.startswith("iso27001_"): + # Generate ISO27001 Finding Object + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + iso27001 = NHNISO27001( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(iso27001) + iso27001.batch_write_data_to_file() + else: + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + generic_compliance = GenericCompliance( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + create_file_descriptor=True, + file_path=filename, + ) + generated_outputs["compliance"].append(generic_compliance) + generic_compliance.batch_write_data_to_file() + # AWS Security Hub Integration if provider == "aws": # Send output to S3 if needed (-B / -D) for all the output formats diff --git a/prowler/compliance/nhn/__init__.py b/prowler/compliance/nhn/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/compliance/nhn/iso27001_2022_nhn.json b/prowler/compliance/nhn/iso27001_2022_nhn.json new file mode 100644 index 0000000000..d825981469 --- /dev/null +++ b/prowler/compliance/nhn/iso27001_2022_nhn.json @@ -0,0 +1,1313 @@ +{ + "Framework": "ISO27001", + "Version": "2022", + "Provider": "NHN", + "Description": "ISO (the International Organization for Standardization) and IEC (the International Electrotechnical Commission) form the specialized system for worldwide standardization. National bodies that are members of ISO or IEC participate in the development of International Standards through technical committees established by the respective organization to deal with particular fields of technical activity. ISO and IEC technical committees collaborate in fields of mutual interest. Other international organizations, governmental and non-governmental, in liaison with ISO and IEC, also take part in the work.", + "Requirements": [ + { + "Id": "A.5.1", + "Description": "Information security policy and topic-specific policies should be defined, approved by management, published, communicated to and acknowledged by relevant personnel and relevant interested parties, and reviewed at planned intervals and if significant changes occur.", + "Name": "Policies for information security", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.1", + "Objetive_Name": "Policies for information security", + "Check_Summary": "Information security policy and topic-specific policies should be defined, approved by management, published, communicated to and acknowledged by relevant personnel and relevant interested parties, and reviewed at planned intervals and if significant changes occur." + } + ], + "Checks": [] + }, + { + "Id": "A.5.2", + "Description": "Information security roles and responsibilities should be defined and allocated according to the organisation needs.", + "Name": "Roles and Responsibilities", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.2", + "Objetive_Name": "Roles and Responsibilities", + "Check_Summary": "Information security roles and responsibilities should be defined and allocated according to the organisation needs." + } + ], + "Checks": [] + }, + { + "Id": "A.5.3", + "Description": "Conflicting duties and conflicting areas of responsibility should be segregated.", + "Name": "Segregation of Duties", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.3", + "Objetive_Name": "Segregation of Duties", + "Check_Summary": "Conflicting duties and conflicting areas of responsibility should be segregated." + } + ], + "Checks": [] + }, + { + "Id": "A.5.4", + "Description": "Management should require all personnel to apply information security in accordance with the established information security policy, topic-specific policies and procedures of the organization.", + "Name": "Management Responsibilities", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.4", + "Objetive_Name": "Management Responsibilities", + "Check_Summary": "Management should require all personnel to apply information security in accordance with the established information security policy, topic-specific policies and procedures of the organization." + } + ], + "Checks": [] + }, + { + "Id": "A.5.5", + "Description": "The organisation should establish and maintain contact with relevant authorities.", + "Name": "Contact With Authorities", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.5", + "Objetive_Name": "Contact With Authorities", + "Check_Summary": "The organisation should establish and maintain contact with relevant authorities." + } + ], + "Checks": [] + }, + { + "Id": "A.5.6", + "Description": "The organisation should establish and maintain contact with special interest groups or other specialist security forums and professional associations.", + "Name": "Contact With Special Interest Groups", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.6", + "Objetive_Name": "Contact With Special Interest Groups", + "Check_Summary": "The organisation should establish and maintain contact with special interest groups or other specialist security forums and professional associations." + } + ], + "Checks": [] + }, + { + "Id": "A.5.7", + "Description": "Information relating to information security threats should be collected and analysed to produce threat intelligence.", + "Name": "Threat Intelligence", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.7", + "Objetive_Name": "Threat Intelligence", + "Check_Summary": "Information relating to information security threats should be collected and analysed to produce threat intelligence." + } + ], + "Checks": [] + }, + { + "Id": "A.5.8", + "Description": "Information security should be integrated into project management.", + "Name": "Information Security In Project Management", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.8", + "Objetive_Name": "Information Security In Project Management", + "Check_Summary": "Information security should be integrated into project management." + } + ], + "Checks": [] + }, + { + "Id": "A.5.9", + "Description": "An inventory of information and other associated assets, including owners, should be developed and maintained.", + "Name": "Inventory Of Information And Other Associated Assets", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.9", + "Objetive_Name": "Inventory Of Information And Other Associated Assets", + "Check_Summary": "An inventory of information and other associated assets, including owners, should be developed and maintained." + } + ], + "Checks": [] + }, + { + "Id": "A.5.10", + "Description": "Rules for the acceptable use and procedures for handling information and other associated assets should be identified, documented and implemented.", + "Name": "Acceptable Use Of Information And Other Associated Assets", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.10", + "Objetive_Name": "Acceptable Use Of Information And Other Associated Assets", + "Check_Summary": "Rules for the acceptable use and procedures for handling information and other associated assets should be identified, documented and implemented." + } + ], + "Checks": [] + }, + { + "Id": "A.5.11", + "Description": "Personnel and other interested parties as appropriate should return all the organisation’s assets in their possession upon change or termination of their employment, contract or agreement.", + "Name": "Return Of Assets", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.11", + "Objetive_Name": "Return Of Assets", + "Check_Summary": "Personnel and other interested parties as appropriate should return all the organisation’s assets in their possession upon change or termination of their employment, contract or agreement." + } + ], + "Checks": [] + }, + { + "Id": "A.5.12", + "Description": "Information should be classified according to the information security needs of the organisation based on confidentiality, integrity, availability and relevant interested party requirements.", + "Name": "Classification Of Information", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.12", + "Objetive_Name": "Classification Of Information", + "Check_Summary": "Information should be classified according to the information security needs of the organisation based on confidentiality, integrity, availability and relevant interested party requirements." + } + ], + "Checks": [] + }, + { + "Id": "A.5.13", + "Description": "An appropriate set of procedures for information labelling should be developed and implemented in accordance with the information classification scheme adopted by the organisation.", + "Name": "Labelling Of Information", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.13", + "Objetive_Name": "Labelling Of Information", + "Check_Summary": "An appropriate set of procedures for information labelling should be developed and implemented in accordance with the information classification scheme adopted by the organisation." + } + ], + "Checks": [] + }, + { + "Id": "A.5.14", + "Description": "Information transfer rules, procedures, or agreements should be in place for all types of transfer facilities within the organisation and between the organisation and other parties.", + "Name": "Information Transfer", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.14", + "Objetive_Name": "Information Transfer", + "Check_Summary": "Information transfer rules, procedures, or agreements should be in place for all types of transfer facilities within the organisation and between the organisation and other parties." + } + ], + "Checks": [] + }, + { + "Id": "A.5.15", + "Description": "Rules to control physical and logical access to information and other associated assets should be established", + "Name": "Access Control", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.15", + "Objetive_Name": "Access Control", + "Check_Summary": "Rules to control physical and logical access to information and other associated assets should be established" + } + ], + "Checks": [ + "compute_instance_login_user" + ] + }, + { + "Id": "A.5.16", + "Description": "The full lifecycle of identities should be managed.", + "Name": "Identity Management", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.16", + "Objetive_Name": "Identity Management", + "Check_Summary": "The full lifecycle of identities should be managed." + } + ], + "Checks": [] + }, + { + "Id": "A.5.17", + "Description": "Allocation and management of authentication information should be controlled by a management process, including advising personnel on the appropriate handling of authentication information.", + "Name": "Authentication Information", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.17", + "Objetive_Name": "Authentication Information", + "Check_Summary": "Allocation and management of authentication information should be controlled by a management process, including advising personnel on the appropriate handling of authentication information." + } + ], + "Checks": [] + }, + { + "Id": "A.5.18", + "Description": "Access rights to information and other associated assets should be provisioned, reviewed, modified and removed in accordance with the organisation’s topic-specific policy on and rules for access control.", + "Name": "Access Rights", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.18", + "Objetive_Name": "Access Rights", + "Check_Summary": "Access rights to information and other associated assets should be provisioned, reviewed, modified and removed in accordance with the organisation’s topic-specific policy on and rules for access control." + } + ], + "Checks": [ + "compute_instance_login_user" + ] + }, + { + "Id": "A.5.19", + "Description": "Processes and procedures should be defined and implemented to manage the information security risks associated with the use of supplier’s products or services.", + "Name": "Information Security In Supplier Relationships", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.19", + "Objetive_Name": "Information Security In Supplier Relationships", + "Check_Summary": "Processes and procedures should be defined and implemented to manage the information security risks associated with the use of supplier’s products or services." + } + ], + "Checks": [] + }, + { + "Id": "A.5.20", + "Description": "Relevant information security requirements should be established and agreed with each supplier based on the type of supplier relationship.", + "Name": "Addressing Information Security Within Supplier Agreements", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.20", + "Objetive_Name": "Addressing Information Security Within Supplier Agreements", + "Check_Summary": "Relevant information security requirements should be established and agreed with each supplier based on the type of supplier relationship." + } + ], + "Checks": [] + }, + { + "Id": "A.5.21", + "Description": "Processes and procedures should be defined and implemented to manage the information security risks associated with the ICT products and services supply chain.", + "Name": "Managing Information Security In The ICT Supply Chain", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.21", + "Objetive_Name": "Managing Information Security In The ICT Supply Chain", + "Check_Summary": "Processes and procedures should be defined and implemented to manage the information security risks associated with the ICT products and services supply chain." + } + ], + "Checks": [] + }, + { + "Id": "A.5.22", + "Description": "The organisation should regularly monitor, review, evaluate and manage change in supplier information security practices and service delivery.", + "Name": "Monitor, Review And Change Management Of Supplier Services", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.22", + "Objetive_Name": "Monitor, Review And Change Management Of Supplier Services", + "Check_Summary": "The organisation should regularly monitor, review, evaluate and manage change in supplier information security practices and service delivery." + } + ], + "Checks": [] + }, + { + "Id": "A.5.23", + "Description": "Processes for acquisition, use, management and exit from cloud services should be established in accordance with the organisation’s information security requirements.", + "Name": "Information Security For Use Of Cloud Services", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.23", + "Objetive_Name": "Information Security For Use Of Cloud Services", + "Check_Summary": "Processes for acquisition, use, management and exit from cloud services should be established in accordance with the organisation’s information security requirements." + } + ], + "Checks": [] + }, + { + "Id": "A.5.24", + "Description": "The organization should plan and prepare for managing information security incidents by defining, establishing and communicating information security incident management processes, roles and responsibilities.", + "Name": "Information Security Incident Management Planning and Preparation", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.24", + "Objetive_Name": "Information Security Incident Management Planning and Preparation", + "Check_Summary": "The organization should plan and prepare for managing information security incidents by defining, establishing and communicating information security incident management processes, roles and responsibilities." + } + ], + "Checks": [] + }, + { + "Id": "A.5.25", + "Description": "The organisation should assess information security events and decide if they are to be categorised as information security incidents.", + "Name": "Assessment And Decision On Information Security Events", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.25", + "Objetive_Name": "Assessment And Decision On Information Security Events", + "Check_Summary": "The organisation should assess information security events and decide if they are to be categorised as information security incidents." + } + ], + "Checks": [] + }, + { + "Id": "A.5.26", + "Description": "Information security incidents should be responded to in accordance with the documented procedures.", + "Name": "Response To Information Security Incidents", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.26", + "Objetive_Name": "Response To Information Security Incidents", + "Check_Summary": "Information security incidents should be responded to in accordance with the documented procedures." + } + ], + "Checks": [] + }, + { + "Id": "A.5.27", + "Description": "Knowledge gained from information security incidents should be used to strengthen and improve the information security controls.", + "Name": "Learning From Information Security Incidents", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.27", + "Objetive_Name": "Learning From Information Security Incidents", + "Check_Summary": "Knowledge gained from information security incidents should be used to strengthen and improve the information security controls." + } + ], + "Checks": [] + }, + { + "Id": "A.5.28", + "Description": "The organisation should establish and implement procedures for the identification, collection, acquisition and preservation of evidence related to information security events.", + "Name": "Collection Of Evidence", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.28", + "Objetive_Name": "Collection Of Evidence", + "Check_Summary": "The organisation should establish and implement procedures for the identification, collection, acquisition and preservation of evidence related to information security events." + } + ], + "Checks": [] + }, + { + "Id": "A.5.29", + "Description": "The organisation should plan how to maintain information security at an appropriate level during disruption.", + "Name": "Information Security During Disruption", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.29", + "Objetive_Name": "Information Security During Disruption", + "Check_Summary": "The organisation should plan how to maintain information security at an appropriate level during disruption." + } + ], + "Checks": [] + }, + { + "Id": "A.5.30", + "Description": "ICT readiness should be planned, implemented, maintained and tested based on business continuity objectives and ICT continuity requirements. ", + "Name": "Readiness For Business Continuity", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.30", + "Objetive_Name": "Readiness For Business Continuity", + "Check_Summary": "ICT readiness should be planned, implemented, maintained and tested based on business continuity objectives and ICT continuity requirements. " + } + ], + "Checks": [] + }, + { + "Id": "A.5.31", + "Description": "Legal, statutory, regulatory and contractual requirements relevant to information security and the organisations approach to meet these requirements should be identified, documented and kept up to date. ", + "Name": "Legal, statutory, regulatory and contractual requirements", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.31", + "Objetive_Name": "Legal, statutory, regulatory and contractual requirements", + "Check_Summary": "Legal, statutory, regulatory and contractual requirements relevant to information security and the organisations approach to meet these requirements should be identified, documented and kept up to date. " + } + ], + "Checks": [] + }, + { + "Id": "A.5.32", + "Description": "The organisation should implement appropriate procedures to protect intellectual property rights. ", + "Name": "Intellectual Property Rights", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.32", + "Objetive_Name": "Intellectual Property Rights", + "Check_Summary": "The organisation should implement appropriate procedures to protect intellectual property rights. " + } + ], + "Checks": [] + }, + { + "Id": "A.5.33", + "Description": "Records should be protected from loss, destruction, falsification, unauthorised access and unauthorised release.", + "Name": "Protection Of Records", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.33", + "Objetive_Name": "Protection Of Records", + "Check_Summary": "Records should be protected from loss, destruction, falsification, unauthorised access and unauthorised release." + } + ], + "Checks": [] + }, + { + "Id": "A.5.34", + "Description": "The organisation should identify and meet the requirements regarding the preservation of privacy and protection of PII according to applicable laws and regulations and contractual requirements.", + "Name": "Privacy And Protection Of PII", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.34", + "Objetive_Name": "Privacy And Protection Of PII", + "Check_Summary": "The organisation should identify and meet the requirements regarding the preservation of privacy and protection of PII according to applicable laws and regulations and contractual requirements." + } + ], + "Checks": [] + }, + { + "Id": "A.5.35", + "Description": "The organisations approach to managing information security and its implementation including people, processes and technologies should be reviewed independently at planned intervals, or when significant changes occur. ", + "Name": "Independent Review Of Information Security", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.35", + "Objetive_Name": "Independent Review Of Information Security", + "Check_Summary": "The organisations approach to managing information security and its implementation including people, processes and technologies should be reviewed independently at planned intervals, or when significant changes occur. " + } + ], + "Checks": [] + }, + { + "Id": "A.5.36", + "Description": "Compliance with the organisations information security policy, topic-specific policies, rules and standards should be regularly reviewed. ", + "Name": "Compliance With Policies, Rules And Standards For Information Security", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.36", + "Objetive_Name": "Compliance With Policies, Rules And Standards For Information Security", + "Check_Summary": "Compliance with the organisations information security policy, topic-specific policies, rules and standards should be regularly reviewed. " + } + ], + "Checks": [] + }, + { + "Id": "A.5.37", + "Description": "Operating procedures for information processing facilities should be documented and made available to personnel who need them. ", + "Name": "Documented Operating Procedures", + "Attributes": [ + { + "Category": "A.5 Organizational controls", + "Objetive_ID": "A.5.37", + "Objetive_Name": "Documented Operating Procedures", + "Check_Summary": "Operating procedures for information processing facilities should be documented and made available to personnel who need them. " + } + ], + "Checks": [] + }, + { + "Id": "A.6.1", + "Description": "Background verification checks on all candidates to become personnel should be carried out prior to joining the organisation and on an ongoing basis taking into consideration applicable laws, regulations and ethics and be proportional to the business requirements, the classification of the information to be accessed and the perceived risks. ", + "Name": "Screening", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.1", + "Objetive_Name": "Screening", + "Check_Summary": "Background verification checks on all candidates to become personnel should be carried out prior to joining the organisation and on an ongoing basis taking into consideration applicable laws, regulations and ethics and be proportional to the business requirements, the classification of the information to be accessed and the perceived risks. " + } + ], + "Checks": [] + }, + { + "Id": "A.6.2", + "Description": "The employment contractual agreements should state the personnel’s and the organisations responsibilities for information security. ", + "Name": "Terms and Conditions Of Employment", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.2", + "Objetive_Name": "Terms and Conditions Of Employment", + "Check_Summary": "The employment contractual agreements should state the personnel’s and the organisations responsibilities for information security. " + } + ], + "Checks": [] + }, + { + "Id": "A.6.3", + "Description": "Personnel of the organisation and relevant interested parties should receive appropriate information security awareness, education and training and regular updates of the organisations information security policy, topic-specific policies and procedures, as relevant for their job function.", + "Name": "Information Security Awareness, Education And Training", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.3", + "Objetive_Name": "Information Security Awareness, Education And Training", + "Check_Summary": "Personnel of the organisation and relevant interested parties should receive appropriate information security awareness, education and training and regular updates of the organisations information security policy, topic-specific policies and procedures, as relevant for their job function." + } + ], + "Checks": [] + }, + { + "Id": "A.6.4", + "Description": "A disciplinary process should be formalised and communicated to take actions against personnel and other relevant interested parties who have committed an information security policy violation.", + "Name": "Disciplinary Process", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.4", + "Objetive_Name": "Disciplinary Process", + "Check_Summary": "A disciplinary process should be formalised and communicated to take actions against personnel and other relevant interested parties who have committed an information security policy violation." + } + ], + "Checks": [] + }, + { + "Id": "A.6.5", + "Description": "Information security responsibilities and duties that remain valid after termination or change of employment should be defined, enforced and communicated to relevant personnel and other interested parties.", + "Name": "Responsibilities After Termination Or Change Of Employment", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.5", + "Objetive_Name": "Responsibilities After Termination Or Change Of Employment", + "Check_Summary": "Information security responsibilities and duties that remain valid after termination or change of employment should be defined, enforced and communicated to relevant personnel and other interested parties." + } + ], + "Checks": [] + }, + { + "Id": "A.6.6", + "Description": "Confidentiality or non-disclosure agreements reflecting the organisation’s needs for the protection of information should be identified, documented, regularly reviewed and signed by personnel and other relevant interested parties.", + "Name": "Confidentiality Or Non-Disclosure Agreements", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.6", + "Objetive_Name": "Confidentiality Or Non-Disclosure Agreements", + "Check_Summary": "Confidentiality or non-disclosure agreements reflecting the organisation’s needs for the protection of information should be identified, documented, regularly reviewed and signed by personnel and other relevant interested parties." + } + ], + "Checks": [] + }, + { + "Id": "A.6.7", + "Description": "Security measures should be implemented when personnel are working remotely to protect information accessed, processed or stored outside the organisation’s premises.", + "Name": "Remote Working", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.7", + "Objetive_Name": "Remote Working", + "Check_Summary": "Security measures should be implemented when personnel are working remotely to protect information accessed, processed or stored outside the organisation’s premises." + } + ], + "Checks": [] + }, + { + "Id": "A.6.8", + "Description": "The organisation should provide a mechanism for personnel to report observed or suspected information security events through appropriate channels in a timely manner.", + "Name": "Information Security Event Reporting", + "Attributes": [ + { + "Category": "A.6 People controls", + "Objetive_ID": "A.6.8", + "Objetive_Name": "Information Security Event Reporting", + "Check_Summary": "The organisation should provide a mechanism for personnel to report observed or suspected information security events through appropriate channels in a timely manner." + } + ], + "Checks": [] + }, + { + "Id": "A.7.1", + "Description": "To prevent unauthorised physical access, damage and interference to the organisations information and other associated assets.", + "Name": "Physical Security Perimeters", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.1", + "Objetive_Name": "Physical Security Perimeters", + "Check_Summary": "To prevent unauthorised physical access, damage and interference to the organisations information and other associated assets." + } + ], + "Checks": [] + }, + { + "Id": "A.7.2", + "Description": "Secure areas should be protected by appropriate entry controls and access points.", + "Name": "Physical Entry", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.2", + "Objetive_Name": "Physical Entry", + "Check_Summary": "Secure areas should be protected by appropriate entry controls and access points." + } + ], + "Checks": [] + }, + { + "Id": "A.7.3", + "Description": "Physical security for offices, rooms and facilities should be designed and implemented.", + "Name": "Securing Offices, Rooms And Facilities", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.3", + "Objetive_Name": "Securing Offices, Rooms And Facilities", + "Check_Summary": "Physical security for offices, rooms and facilities should be designed and implemented." + } + ], + "Checks": [] + }, + { + "Id": "A.7.4", + "Description": "Premises should be continuously monitored for unauthorised physical access.", + "Name": "Physical Security Monitoring", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.4", + "Objetive_Name": "Physical Security Monitoring", + "Check_Summary": "Premises should be continuously monitored for unauthorised physical access." + } + ], + "Checks": [] + }, + { + "Id": "A.7.5", + "Description": "Protection against physical and environmental threats, such as natural disasters and other intentional or unintentional physical threats to infrastructure should be designed and implemented.", + "Name": "Protecting Against Physical and Environmental Threats", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.5", + "Objetive_Name": "Protecting Against Physical and Environmental Threats", + "Check_Summary": "Protection against physical and environmental threats, such as natural disasters and other intentional or unintentional physical threats to infrastructure should be designed and implemented." + } + ], + "Checks": [] + }, + { + "Id": "A.7.6", + "Description": "Security measures for working in secure areas should be designed and implemented.", + "Name": "Working In Secure Areas", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.6", + "Objetive_Name": "Working In Secure Areas", + "Check_Summary": "Security measures for working in secure areas should be designed and implemented." + } + ], + "Checks": [] + }, + { + "Id": "A.7.7", + "Description": "Clear desk rules for papers and removable storage media and clear screen rules for information processing facilities should be defined and appropriately enforced.", + "Name": "Clear Desk And Clear Screen", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.7", + "Objetive_Name": "Clear Desk And Clear Screen", + "Check_Summary": "Clear desk rules for papers and removable storage media and clear screen rules for information processing facilities should be defined and appropriately enforced." + } + ], + "Checks": [] + }, + { + "Id": "A.7.8", + "Description": "Equipment should be sited securely and protected.", + "Name": "Equipment Siting And Protection", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.8", + "Objetive_Name": "Equipment Siting And Protection", + "Check_Summary": "Equipment should be sited securely and protected." + } + ], + "Checks": [] + }, + { + "Id": "A.7.9", + "Description": "Off-site assets should be protected.", + "Name": "Security Of Assets Off-Premises", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.9", + "Objetive_Name": "Security Of Assets Off-Premises", + "Check_Summary": "Off-site assets should be protected." + } + ], + "Checks": [] + }, + { + "Id": "A.7.10", + "Description": "Storage media should be managed through their life cycle of acquisition, use, transportation and disposal in accordance with the organisations classification scheme and handling requirements.", + "Name": "Storage Media", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.10", + "Objetive_Name": "Storage Media", + "Check_Summary": "Storage media should be managed through their life cycle of acquisition, use, transportation and disposal in accordance with the organisations classification scheme and handling requirements." + } + ], + "Checks": [] + }, + { + "Id": "A.7.11", + "Description": "Information processing facilities should be protected from power failures and other disruptions caused by failures in supporting utilities.", + "Name": "Supporting Utilities", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.11", + "Objetive_Name": "Supporting Utilities", + "Check_Summary": "Information processing facilities should be protected from power failures and other disruptions caused by failures in supporting utilities." + } + ], + "Checks": [] + }, + { + "Id": "A.7.12", + "Description": "Cables carrying power, data or supporting information services should be protected from interception", + "Name": "Cabling Security", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.12", + "Objetive_Name": "Cabling Security", + "Check_Summary": "Cables carrying power, data or supporting information services should be protected from interception" + } + ], + "Checks": [] + }, + { + "Id": "A.7.13", + "Description": "Equipment should be maintained correctly to ensure availability, integrity and confidentiality of information.", + "Name": "Equipment Maintenance", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.13", + "Objetive_Name": "Equipment Maintenance", + "Check_Summary": "Equipment should be maintained correctly to ensure availability, integrity and confidentiality of information." + } + ], + "Checks": [] + }, + { + "Id": "A.7.14", + "Description": "Items of equipment containing storage media should be verified to ensure that any sensitive data and licensed software has been removed or securely overwritten prior to disposal or re-use.", + "Name": "Secure Disposal Or Re-Use Of Equipment", + "Attributes": [ + { + "Category": "A.7 Physical controls", + "Objetive_ID": "A.7.14", + "Objetive_Name": "Secure Disposal Or Re-Use Of Equipment", + "Check_Summary": "Items of equipment containing storage media should be verified to ensure that any sensitive data and licensed software has been removed or securely overwritten prior to disposal or re-use." + } + ], + "Checks": [] + }, + { + "Id": "A.8.1", + "Description": "Information stored on, processed by or accessible via user endpoint devices should be protected.", + "Name": "User Endpoint Devices", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.1", + "Objetive_Name": "User Endpoint Devices", + "Check_Summary": "Information stored on, processed by or accessible via user endpoint devices should be protected." + } + ], + "Checks": [] + }, + { + "Id": "A.8.2", + "Description": "The allocation and use of privileged access rights should be restricted and managed.", + "Name": "Privileged Access Rights", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.2", + "Objetive_Name": "Privileged Access Rights", + "Check_Summary": "The allocation and use of privileged access rights should be restricted and managed." + } + ], + "Checks": [ + "compute_instance_login_user" + ] + }, + { + "Id": "A.8.3", + "Description": "Access to information and other associated assets should be restricted in accordance with the established topic-specific policy on access control.", + "Name": "Information Access Restriction", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.3", + "Objetive_Name": "Information Access Restriction", + "Check_Summary": "Access to information and other associated assets should be restricted in accordance with the established topic-specific policy on access control." + } + ], + "Checks": [] + }, + { + "Id": "A.8.4", + "Description": "Read and write access to source code, development tools and software libraries should be appropriately managed.", + "Name": "Access To Source Code", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.4", + "Objetive_Name": "Access To Source Code", + "Check_Summary": "Read and write access to source code, development tools and software libraries should be appropriately managed." + } + ], + "Checks": [] + }, + { + "Id": "A.8.5", + "Description": "Secure authentication technologies and procedures should be implemented based on information access restrictions and the topic-specific policy on access control.", + "Name": "Secure Authentication", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.5", + "Objetive_Name": "Secure Authentication", + "Check_Summary": "Secure authentication technologies and procedures should be implemented based on information access restrictions and the topic-specific policy on access control." + } + ], + "Checks": [] + }, + { + "Id": "A.8.6", + "Description": "The use of resources should be monitored and adjusted in line with current and expected capacity requirements.", + "Name": "Capacity Management", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.6", + "Objetive_Name": "Capacity Management", + "Check_Summary": "The use of resources should be monitored and adjusted in line with current and expected capacity requirements." + } + ], + "Checks": [] + }, + { + "Id": "A.8.7", + "Description": "Protection against malware should be implemented and supported by appropriate user awareness.", + "Name": "Protection Against Malware", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.7", + "Objetive_Name": "Protection Against Malware", + "Check_Summary": "Protection against malware should be implemented and supported by appropriate user awareness." + } + ], + "Checks": [] + }, + { + "Id": "A.8.8", + "Description": "Information about technical vulnerabilities of information systems in use should be obtained, the organisations exposure to such vulnerabilities should be evaluated and appropriate measures should be taken.", + "Name": "Management of Technical Vulnerabilities", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.8", + "Objetive_Name": "Management of Technical Vulnerabilities", + "Check_Summary": "Information about technical vulnerabilities of information systems in use should be obtained, the organisations exposure to such vulnerabilities should be evaluated and appropriate measures should be taken." + } + ], + "Checks": [] + }, + { + "Id": "A.8.9", + "Description": "Configurations, including security configurations, of hardware, software, services and networks should be established, documented, implemented, monitored and reviewed.", + "Name": "Configuration Management", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.9", + "Objetive_Name": "Configuration Management", + "Check_Summary": "Configurations, including security configurations, of hardware, software, services and networks should be established, documented, implemented, monitored and reviewed." + } + ], + "Checks": [ + "compute_instance_security_groups", + "network_vpc_subnet_enable_dhcp" + ] + }, + { + "Id": "A.8.10", + "Description": "Information stored in information systems, devices or in any other storage media should be deleted when no longer required.", + "Name": "Information Deletion", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.10", + "Objetive_Name": "Information Deletion", + "Check_Summary": "Information stored in information systems, devices or in any other storage media should be deleted when no longer required." + } + ], + "Checks": [] + }, + { + "Id": "A.8.11", + "Description": "Data masking should be used in accordance with the organisation’s topic-specific policy on access control and other related topic-specific policies, and business requirements, taking applicable legislation into consideration.", + "Name": "Data Masking", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.11", + "Objetive_Name": "Data Masking", + "Check_Summary": "Data masking should be used in accordance with the organisation’s topic-specific policy on access control and other related topic-specific policies, and business requirements, taking applicable legislation into consideration." + } + ], + "Checks": [] + }, + { + "Id": "A.8.12", + "Description": "Data leakage prevention measures should be applied to systems, networks and any other devices that process, store or transmit sensitive information.", + "Name": "Data Leakage Prevention", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.12", + "Objetive_Name": "Data Leakage Prevention", + "Check_Summary": "Data leakage prevention measures should be applied to systems, networks and any other devices that process, store or transmit sensitive information." + } + ], + "Checks": [] + }, + { + "Id": "A.8.13", + "Description": "Backup copies of information, software and systems should be maintained and regularly tested in accordance with the agreed topic-specific policy on backup.", + "Name": "Information Backup", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.13", + "Objetive_Name": "Information Backup", + "Check_Summary": "Backup copies of information, software and systems should be maintained and regularly tested in accordance with the agreed topic-specific policy on backup." + } + ], + "Checks": [] + }, + { + "Id": "A.8.14", + "Description": "Information processing facilities should be implemented with redundancy sufficient to meet availability", + "Name": "Redundancy of information processing facilities", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.14", + "Objetive_Name": "Redundancy of information processing facilities", + "Check_Summary": "Information processing facilities should be implemented with redundancy sufficient to meet availability" + } + ], + "Checks": [] + }, + { + "Id": "A.8.15", + "Description": "Logs that record activities, exceptions, faults and other relevant events should be produced, stored, protected and analysed.", + "Name": "Logging", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.15", + "Objetive_Name": "Logging", + "Check_Summary": "Logs that record activities, exceptions, faults and other relevant events should be produced, stored, protected and analysed." + } + ], + "Checks": [] + }, + { + "Id": "A.8.16", + "Description": "Networks, systems and applications should be monitored for anomalous behaviour and appropriate actions taken to evaluate potential information security incidents.", + "Name": "Monitoring Activities", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.16", + "Objetive_Name": "Monitoring Activities", + "Check_Summary": "Networks, systems and applications should be monitored for anomalous behaviour and appropriate actions taken to evaluate potential information security incidents." + } + ], + "Checks": [] + }, + { + "Id": "A.8.17", + "Description": "The clocks of information processing systems used by the organisation should be synchronised to approved time sources.", + "Name": "Clock Synchronisation", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.17", + "Objetive_Name": "Clock Synchronisation", + "Check_Summary": "The clocks of information processing systems used by the organisation should be synchronised to approved time sources." + } + ], + "Checks": [] + }, + { + "Id": "A.8.18", + "Description": "The use of utility programs that can be capable of overriding system and application controls should be restricted and tightly controlled", + "Name": "Use of Privileged Utility Programs", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.18", + "Objetive_Name": "Use of Privileged Utility Programs", + "Check_Summary": "The use of utility programs that can be capable of overriding system and application controls should be restricted and tightly controlled" + } + ], + "Checks": [] + }, + { + "Id": "A.8.19", + "Description": "Procedures and measures should be implemented to securely manage software installation on operational systems.", + "Name": "Installation of Software on Operational Systems", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.19", + "Objetive_Name": "Installation of Software on Operational Systems", + "Check_Summary": "Procedures and measures should be implemented to securely manage software installation on operational systems." + } + ], + "Checks": [] + }, + { + "Id": "A.8.20", + "Description": "Networks and network devices should be secured, managed and controlled to protect information in systems and applications.", + "Name": "Network Security", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.20", + "Objetive_Name": "Network Security", + "Check_Summary": "Networks and network devices should be secured, managed and controlled to protect information in systems and applications." + } + ], + "Checks": [ + "compute_instance_public_ip", + "compute_instance_security_groups", + "network_vpc_has_empty_routingtables", + "network_vpc_subnet_has_external_router" + ] + }, + { + "Id": "A.8.21", + "Description": "Security mechanisms, service levels and service requirements of network services should be identified, implemented and monitored.", + "Name": "Security of Network Services", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.21", + "Objetive_Name": "Security of Network Services", + "Check_Summary": "Security mechanisms, service levels and service requirements of network services should be identified, implemented and monitored." + } + ], + "Checks": [] + }, + { + "Id": "A.8.22", + "Description": "Security mechanisms, service levels and service requirements of network services should be identified, implemented and monitored.", + "Name": "Segregation of Networks", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.22", + "Objetive_Name": "Segregation of Networks", + "Check_Summary": "Security mechanisms, service levels and service requirements of network services should be identified, implemented and monitored." + } + ], + "Checks": [ + "compute_instance_public_ip", + "network_vpc_subnet_has_external_router" + ] + }, + { + "Id": "A.8.23", + "Description": "Access to external websites should be managed to reduce exposure to malicious content.", + "Name": "Web Filtering", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.23", + "Objetive_Name": "Web Filtering", + "Check_Summary": "Access to external websites should be managed to reduce exposure to malicious content." + } + ], + "Checks": [] + }, + { + "Id": "A.8.24", + "Description": "Rules for the effective use of cryptography, including cryptographic key management, should be defined and implemented.", + "Name": "Use of Cryptography", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.24", + "Objetive_Name": "Use of Cryptography", + "Check_Summary": "Rules for the effective use of cryptography, including cryptographic key management, should be defined and implemented." + } + ], + "Checks": [] + }, + { + "Id": "A.8.25", + "Description": "Rules for the secure development of software and systems should be established and applied.", + "Name": "Secure Development Life Cycle", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.25", + "Objetive_Name": "Secure Development Life Cycle", + "Check_Summary": "Rules for the secure development of software and systems should be established and applied." + } + ], + "Checks": [] + }, + { + "Id": "A.8.26", + "Description": "Information security requirements should be identified, specified and approved when developing or acquiring applications.", + "Name": "Application Security Requirements", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.26", + "Objetive_Name": "Application Security Requirements", + "Check_Summary": "Information security requirements should be identified, specified and approved when developing or acquiring applications." + } + ], + "Checks": [] + }, + { + "Id": "A.8.27", + "Description": "Principles for engineering secure systems should be established, documented, maintained and applied to any information system development activities.", + "Name": "Secure Systems Architecture and Engineering Principles", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.27", + "Objetive_Name": "Secure Systems Architecture and Engineering Principles", + "Check_Summary": "Principles for engineering secure systems should be established, documented, maintained and applied to any information system development activities." + } + ], + "Checks": [] + }, + { + "Id": "A.8.29", + "Description": "Security testing processes should be defined and implemented in the development life cycle.", + "Name": "Security Testing in Development and Acceptance", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.29", + "Objetive_Name": "Security Testing in Development and Acceptance", + "Check_Summary": "Security testing processes should be defined and implemented in the development life cycle." + } + ], + "Checks": [] + }, + { + "Id": "A.8.30", + "Description": "The organisation should direct, monitor and review the activities related to outsourced system development.", + "Name": "Outsourced Development", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.30", + "Objetive_Name": "Outsourced Development", + "Check_Summary": "The organisation should direct, monitor and review the activities related to outsourced system development." + } + ], + "Checks": [] + }, + { + "Id": "A.8.31", + "Description": "Development, testing and production environments should be separated and secured.", + "Name": "Separation of Development, Test and Production Environments", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.31", + "Objetive_Name": "Separation of Development, Test and Production Environments", + "Check_Summary": "Development, testing and production environments should be separated and secured." + } + ], + "Checks": [] + }, + { + "Id": "A.8.32", + "Description": "Changes to information processing facilities and information systems should be subject to change management procedures.", + "Name": "Change Management", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.32", + "Objetive_Name": "Change Management", + "Check_Summary": "Changes to information processing facilities and information systems should be subject to change management procedures." + } + ], + "Checks": [] + }, + { + "Id": "A.8.33", + "Description": "Test information should be appropriately selected, protected and managed.", + "Name": "Test Information", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.33", + "Objetive_Name": "Test Information", + "Check_Summary": "Test information should be appropriately selected, protected and managed." + } + ], + "Checks": [] + }, + { + "Id": "A.8.34", + "Description": "Audit tests and other assurance activities involving assessment of operational systems should be planned and agreed between the tester and appropriate management.", + "Name": "Protection of Information Systems During Audit Testing", + "Attributes": [ + { + "Category": "A.8 Technological controls", + "Objetive_ID": "A.8.34", + "Objetive_Name": "Protection of Information Systems During Audit Testing", + "Check_Summary": "Audit tests and other assurance activities involving assessment of operational systems should be planned and agreed between the tester and appropriate management." + } + ], + "Checks": [] + } + ] +} diff --git a/prowler/config/config.py b/prowler/config/config.py index 9c5a4021a6..6089a24514 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -29,6 +29,7 @@ class Provider(str, Enum): AZURE = "azure" KUBERNETES = "kubernetes" MICROSOFT365 = "microsoft365" + NHN = "nhn" # Compliance diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index 7dba878217..b76424f495 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -573,6 +573,29 @@ class CheckReportMicrosoft365(Check_Report): self.location = resource_location +@dataclass +class CheckReportNHN(Check_Report): + """Contains the NHN Check's finding information.""" + + resource_name: str + resource_id: str + location: str + + def __init__(self, metadata: Dict, resource: Any) -> None: + """Initialize the NHN Check's finding information. + + Args: + metadata: The metadata of the check. + resource: Basic information about the resource. Defaults to None. + """ + super().__init__(metadata, resource) + self.resource_name = getattr( + resource, "name", getattr(resource, "resource_name", "") + ) + self.resource_id = getattr(resource, "id", getattr(resource, "resource_id", "")) + self.location = getattr(resource, "location", "kr1") + + # Testing Pending def load_check_metadata(metadata_file: str) -> CheckMetadata: """ diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index cff8940134..0a5f63074d 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -26,15 +26,16 @@ class ProwlerArgumentParser: self.parser = argparse.ArgumentParser( prog="prowler", formatter_class=RawTextHelpFormatter, - usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,dashboard} ...", + usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,nhn,dashboard} ...", epilog=""" Available Cloud Providers: - {aws,azure,gcp,kubernetes} + {aws,azure,gcp,kubernetes,microsoft365,nhn} aws AWS Provider azure Azure Provider gcp GCP Provider kubernetes Kubernetes Provider microsoft365 Microsoft 365 Provider + nhn NHN Provider (Unofficial) Available components: dashboard Local dashboard diff --git a/prowler/lib/outputs/compliance/iso27001/iso27001_nhn.py b/prowler/lib/outputs/compliance/iso27001/iso27001_nhn.py new file mode 100644 index 0000000000..03bbfa7195 --- /dev/null +++ b/prowler/lib/outputs/compliance/iso27001/iso27001_nhn.py @@ -0,0 +1,87 @@ +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.iso27001.models import NHNISO27001Model +from prowler.lib.outputs.finding import Finding + + +class NHNISO27001(ComplianceOutput): + """ + This class represents the NHN ISO 27001 compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into NHN ISO 27001 compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into NHN ISO 27001 compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = NHNISO27001Model( + Provider=finding.provider, + Description=compliance.Description, + AccountId=finding.account_uid, + Region=finding.region, + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Category=attribute.Category, + Requirements_Attributes_Objetive_ID=attribute.Objetive_ID, + Requirements_Attributes_Objetive_Name=attribute.Objetive_Name, + Requirements_Attributes_Check_Summary=attribute.Check_Summary, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + CheckId=finding.check_id, + Muted=finding.muted, + ResourceName=finding.resource_name, + ) + self._data.append(compliance_row) + + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = NHNISO27001Model( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + AccountId="", + Region="", + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Category=attribute.Category, + Requirements_Attributes_Objetive_ID=attribute.Objetive_ID, + Requirements_Attributes_Objetive_Name=attribute.Objetive_Name, + Requirements_Attributes_Check_Summary=attribute.Check_Summary, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/iso27001/models.py b/prowler/lib/outputs/compliance/iso27001/models.py index 1d84b5c892..16e97a178d 100644 --- a/prowler/lib/outputs/compliance/iso27001/models.py +++ b/prowler/lib/outputs/compliance/iso27001/models.py @@ -99,3 +99,28 @@ class KubernetesISO27001Model(BaseModel): CheckId: str Muted: bool ResourceName: str + + +class NHNISO27001Model(BaseModel): + """ + NHNISO27001Model generates a finding's output in CSV NHN ISO27001 format. + """ + + Provider: str + Description: str + AccountId: str + Region: str + AssessmentDate: str + Requirements_Id: str + Requirements_Name: str + Requirements_Description: str + Requirements_Attributes_Category: str + Requirements_Attributes_Objetive_ID: str + Requirements_Attributes_Objetive_Name: str + Requirements_Attributes_Check_Summary: str + Status: str + StatusExtended: str + ResourceId: str + CheckId: str + Muted: bool + ResourceName: str diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index 58d21487c0..a1e68047fa 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -259,6 +259,21 @@ class Finding(BaseModel): output_data["resource_uid"] = check_output.resource_id output_data["region"] = check_output.location + elif provider.type == "nhn": + output_data["auth_method"] = ( + f"passwordCredentials: username={get_nested_attribute(provider, '_identity.username')}, " + f"tenantId={get_nested_attribute(provider, '_identity.tenant_id')}" + ) + output_data["account_uid"] = get_nested_attribute( + provider, "identity.tenant_id" + ) + output_data["account_name"] = get_nested_attribute( + provider, "identity.tenant_domain" + ) + output_data["resource_name"] = check_output.resource_name + output_data["resource_uid"] = check_output.resource_id + output_data["region"] = check_output.location + # check_output Unique ID # TODO: move this to a function # TODO: in Azure, GCP and K8s there are findings without resource_name diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index de99168326..8e3c88efd6 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -591,6 +591,51 @@ class HTML(Output): ) return "" + def get_nhn_assessment_summary(provider: Provider) -> str: + """ + get_nhn_assessment_summary gets the HTML assessment summary for the provider + + Args: + provider (Provider): the provider object + + Returns: + str: the HTML assessment summary + """ + try: + return f""" +
    +
    +
    + NHN Assessment Summary +
    +
      +
    • + NHN Tenant Domain: {provider.identity.tenant_domain} +
    • +
    +
    +
    +
    +
    +
    + NHN Credentials +
    +
      +
    • + NHN Identity Type: {provider.identity.identity_type} +
    • +
    • + NHN Identity ID: {provider.identity.identity_id} +
    • +
    +
    +
    """ + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) + return "" + @staticmethod def get_assessment_summary(provider: Provider) -> str: """ diff --git a/prowler/lib/outputs/outputs.py b/prowler/lib/outputs/outputs.py index dfd37429dd..0912f986af 100644 --- a/prowler/lib/outputs/outputs.py +++ b/prowler/lib/outputs/outputs.py @@ -18,6 +18,8 @@ def stdout_report(finding, color, verbose, status, fix): details = finding.namespace.lower() if finding.check_metadata.Provider == "microsoft365": details = finding.location + if finding.check_metadata.Provider == "nhn": + details = finding.location if (verbose or fix) and (not status or finding.status in status): if finding.muted: diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index 63d4480f80..b860285e2e 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -43,6 +43,9 @@ def display_summary_table( elif provider.type == "microsoft365": entity_type = "Tenant Domain" audited_entities = provider.identity.tenant_domain + elif provider.type == "nhn": + entity_type = "Tenant Domain" + audited_entities = provider.identity.tenant_domain # Check if there are findings and that they are not all MANUAL if findings and not all(finding.status == "MANUAL" for finding in findings): diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index ec9c5de0db..b8fe46d9e8 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -222,6 +222,15 @@ class Provider(ABC): tenant_id=arguments.tenant_id, fixer_config=fixer_config, ) + elif "nhn" in provider_class_name.lower(): + provider_class( + username=arguments.nhn_username, + password=arguments.nhn_password, + tenant_id=arguments.nhn_tenant_id, + config_path=arguments.config_file, + mutelist_path=arguments.mutelist_file, + fixer_config=fixer_config, + ) except TypeError as error: logger.critical( diff --git a/prowler/providers/nhn/__init__.py b/prowler/providers/nhn/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/exceptions/exceptions.py b/prowler/providers/nhn/exceptions/exceptions.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/lib/__init__.py b/prowler/providers/nhn/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/lib/arguments/__init__.py b/prowler/providers/nhn/lib/arguments/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/lib/arguments/arguments.py b/prowler/providers/nhn/lib/arguments/arguments.py new file mode 100644 index 0000000000..d4925090e6 --- /dev/null +++ b/prowler/providers/nhn/lib/arguments/arguments.py @@ -0,0 +1,17 @@ +def init_parser(self): + """Init the NHN Provider CLI parser""" + nhn_parser = self.subparsers.add_parser( + "nhn", parents=[self.common_providers_parser], help="NHN Provider" + ) + + # Authentication + nhn_auth_subparser = nhn_parser.add_argument_group("Authentication") + nhn_auth_subparser.add_argument( + "--nhn-username", nargs="?", default=None, help="NHN API Username" + ) + nhn_auth_subparser.add_argument( + "--nhn-password", nargs="?", default=None, help="NHN API Password" + ) + nhn_auth_subparser.add_argument( + "--nhn-tenant-id", nargs="?", default=None, help="NHN Tenant ID" + ) diff --git a/prowler/providers/nhn/lib/mutelist/__init__.py b/prowler/providers/nhn/lib/mutelist/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/lib/mutelist/mutelist.py b/prowler/providers/nhn/lib/mutelist/mutelist.py new file mode 100644 index 0000000000..14144d00f8 --- /dev/null +++ b/prowler/providers/nhn/lib/mutelist/mutelist.py @@ -0,0 +1,14 @@ +from prowler.lib.check.models import CheckReportNHN +from prowler.lib.mutelist.mutelist import Mutelist +from prowler.lib.outputs.utils import unroll_dict, unroll_tags + + +class NHNMutelist(Mutelist): + def is_finding_muted(self, finding: CheckReportNHN) -> bool: + return self.is_muted( + finding.resource_id, + finding.check_metadata.CheckID, + finding.location, + finding.resource_name, + unroll_dict(unroll_tags(finding.resource_tags)), + ) diff --git a/prowler/providers/nhn/lib/service/__init__.py b/prowler/providers/nhn/lib/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/lib/service/service.py b/prowler/providers/nhn/lib/service/service.py new file mode 100644 index 0000000000..36781b8895 --- /dev/null +++ b/prowler/providers/nhn/lib/service/service.py @@ -0,0 +1 @@ +# TODO: If more services are added, we need to add common methods here diff --git a/prowler/providers/nhn/models.py b/prowler/providers/nhn/models.py new file mode 100644 index 0000000000..0288e1be5d --- /dev/null +++ b/prowler/providers/nhn/models.py @@ -0,0 +1,56 @@ +from pydantic import BaseModel + +from prowler.config.config import output_file_timestamp +from prowler.providers.common.models import ProviderOutputOptions + + +class NHNIdentityInfo(BaseModel): + """ + NHNIdentityInfo holds basic identity fields for the NHN provider. + + Attributes: + - identity_id (str): An optional identity ID if used by NHN services. + - identity_type (str): The type or role of the identity, if needed. + - tenant_domain (str): The tenant domain if applicable. + (Some NHN services might require a domain or project domain.) + - tenant_id (str): The tenant ID for the NHN Cloud account. + - username (str): The username associated with the account. + """ + + identity_id: str = "" + identity_type: str = "" + tenant_domain: str = "" + tenant_id: str + username: str + + +class NHNOutputOptions(ProviderOutputOptions): + """ + NHNOutputOptions overrides ProviderOutputOptions for NHN-specific output logic. + For example, generating a filename that includes the NHN tenant_id. + + Attributes inherited from ProviderOutputOptions: + - output_filename (str): The base filename used for generated reports. + - output_directory (str): The directory to store the output files. + - ... see ProviderOutputOptions for more details. + + Methods: + - __init__: Customizes the output filename logic for NHN. + """ + + def __init__(self, arguments, bulk_checks_metadata, identity: NHNIdentityInfo): + super().__init__(arguments, bulk_checks_metadata) + + # If --output-filename is not specified, build a default name. + if not getattr(arguments, "output_filename", None): + # If tenant_id exists, include it in the filename (e.g., prowler-output-nhn--20230101) + if identity.tenant_id: + self.output_filename = ( + f"prowler-output-nhn-{identity.tenant_id}-{output_file_timestamp}" + ) + # Otherwise just 'prowler-output-nhn-' + else: + self.output_filename = f"prowler-output-nhn-{output_file_timestamp}" + # If --output-filename was explicitly given, respect that + else: + self.output_filename = arguments.output_filename diff --git a/prowler/providers/nhn/nhn_provider.py b/prowler/providers/nhn/nhn_provider.py new file mode 100644 index 0000000000..3e179d694b --- /dev/null +++ b/prowler/providers/nhn/nhn_provider.py @@ -0,0 +1,308 @@ +import os +from typing import Optional + +import requests +from colorama import Style + +from prowler.config.config import ( + default_config_file_path, + get_default_mute_file_path, + load_and_validate_config_file, +) +from prowler.lib.logger import logger +from prowler.lib.utils.utils import print_boxes +from prowler.providers.common.models import Audit_Metadata, Connection +from prowler.providers.common.provider import Provider +from prowler.providers.nhn.lib.mutelist.mutelist import NHNMutelist +from prowler.providers.nhn.models import NHNIdentityInfo + + +class NhnProvider(Provider): + """ + NHN Provider class to handle the NHN provider + + Attributes: + - _type: str -> The type of the provider, which is set to "nhn". + - _session: requests.Session -> The session object associated with the NHN provider. + - _identity: NHNIdentityInfo -> The identity information for the NHN provider. + - _audit_config: dict -> The audit configuration for the NHN provider. + - _mutelist: NHNMutelist -> The mutelist object associated with the NHN provider. + - audit_metadata: Audit_Metadata -> The audit metadata for the NHN provider. + + Methods: + - __init__: Initializes the NHN provider. + - type: Returns the type of the NHN provider. + - identity: Returns the identity of the NHN provider.(ex: tenant_id, username) + - session: Returns the session object associated with the NHN provider.(ex: Bearer token) + - audit_config: Returns the audit configuration for the NHN provider. + - fixer_config: Returns the fixer configuration. + - mutelist: Returns the mutelist object associated with the NHN provider. + - validate_arguments: Validates the NHN provider arguments.(ex: username, password, tenant_id) + - print_credentials: Prints the NHN credentials information.(ex: username, tenant_id) + - setup_session: Set up the NHN session with the specified authentication method. + - test_connection: tests the provider connection + """ + + _type: str = "nhn" + _session: Optional[requests.Session] + _identity: NHNIdentityInfo + _audit_config: dict + _mutelist: NHNMutelist + # TODO: this is not optional, enforce for all providers + audit_metadata: Audit_Metadata + + def __init__( + self, + username: str = None, + password: str = None, + tenant_id: str = None, + config_path: str = None, + fixer_config: dict = None, + mutelist_path: str = None, + mutelist_content: dict = None, + ): + """ + Initializes the NHN provider. + + Args: + - username: The NHN Cloud client ID + - password: The NHN Cloud client password + - tenant_id: The NHN Cloud Tenant ID + - config_path: The path to the configuration file. + - fixer_config: The fixer configuration. + - mutelist_path: The path to the mutelist file. + - mutelist_content: The mutelist content. + """ + logger.info("Initializing Nhn Provider...") + + # 1) Store argument values + self._username = username or os.getenv("NHN_USERNAME") + self._password = password or os.getenv("NHN_PASSWORD") + self._tenant_id = tenant_id or os.getenv("NHN_TENANT_ID") + + if not all([self._username, self._password, self._tenant_id]): + raise ValueError("NhnProvider requires username, password and tenant_id") + + # 2) Load audit_config, fixer_config, mutelist + self._fixer_config = fixer_config if fixer_config else {} + if not config_path: + config_path = default_config_file_path + self._audit_config = load_and_validate_config_file(self._type, config_path) + + if mutelist_content: + self._mutelist = NHNMutelist(mutelist_content=mutelist_content) + else: + if not mutelist_path: + mutelist_path = get_default_mute_file_path(self._type) + self._mutelist = NHNMutelist(mutelist_path=mutelist_path) + + # 3) Initialize session/token + self._token = None + self._session = None + self.setup_session() + + # 4) Create NHNIdentityInfo object + self._identity = NHNIdentityInfo( + tenant_id=self._tenant_id, + username=self._username, + ) + + Provider.set_global_provider(self) + + @property + def type(self) -> str: + """ + Returns the type of the provider ("nhn"). + """ + return self._type + + @property + def identity(self) -> str: + """ + Returns the NHNIdentityInfo object, which may contain tenant_id, username, etc. + """ + return self._identity + + @property + def session(self) -> str: + """ + Returns the requests.Session object for NHN API calls. + """ + return self._session + + @property + def audit_config(self) -> dict: + """ + Returns the audit configuration loaded from file or default settings. + """ + return self._audit_config + + @property + def fixer_config(self) -> dict: + """ + Returns any fixer configuration provided to the NHN provider. + """ + return self._fixer_config + + @property + def mutelist(self) -> dict: + """ + Returns the NHNMutelist object for handling any muted checks. + """ + return self._mutelist + + @staticmethod + def validate_arguments(username: str, password: str, tenant_id: str) -> None: + """ + Ensures that username, password, and tenant_id are not empty. + """ + if not username or not password or not tenant_id: + raise ValueError("NHN Provider requires username, password and tenant_id.") + + def print_credentials(self) -> None: + """ + Prints the NHN credentials in a simple box format. + """ + report_lines = [ + f" Username: {self._username}", + f" TenantID: {self._tenant_id}", + ] + report_title = ( + f"{Style.BRIGHT}Using the NHN credentials below:{Style.RESET_ALL}" + ) + print_boxes(report_lines, report_title) + + def setup_session(self) -> None: + """ + Implement NHN Cloud Authentication method by calling Keystone v2.0 API(POST /v2.0/tokens). + ex) https://api-identity-infrastructure.nhncloudservice.com/v2.0/tokens + { + "auth": { + "tenantId": "f5073eaa26b64cffbee89411df94ce01", + "passwordCredentials": { + "username": "user@example.com", + "password": "secretsecret" + } + } + } + + On success, it creates a requests.Session and sets the X-Auth-Token header. + """ + url = "https://api-identity-infrastructure.nhncloudservice.com/v2.0/tokens" + data = { + "auth": { + "tenantId": self._tenant_id, + "passwordCredentials": { + "username": self._username, + "password": self._password, + }, + } + } + try: + response = requests.post(url, json=data, timeout=10) + if response.status_code == 200: + resp_json = response.json() + self._token = resp_json["access"]["token"]["id"] + sess = requests.Session() + sess.headers.update( + {"X-Auth-Token": self._token, "Content-Type": "application/json"} + ) + self._session = sess + logger.info("NHN token acquired successfully and session is set up.") + else: + logger.critical( + f"Failed to get token. Status: {response.status_code}, Body: {response.text}" + ) + raise ValueError("Failed to get NHN token") + except Exception as e: + logger.critical(f"[setup_session] Error: {e}") + raise e + + @staticmethod + def test_connection( + username: str, + password: str, + tenant_id: str, + raise_on_exception: bool = True, + ) -> Connection: + """ + Test connection to NHN Cloud by performing: + 1) Keystone token request + 2) (Optional) a small test API call to confirm credentials are valid + + Args: + username (str): NHN Cloud user ID (email) + password (str): NHN Cloud user password + tenant_id (str): NHN Cloud tenant ID + raise_on_exception (bool): If True, raise the caught exception; + if False, return Connection(error=exception). + + Returns: + Connection: + Connection(is_connected=True) if success, + otherwise Connection(error=Exception or custom error). + """ + try: + # 1) Validate arguments (예: username/password/tenant_id) + if not username or not password or not tenant_id: + error_msg = ( + "NHN test_connection error: missing username/password/tenant_id" + ) + logger.error(error_msg) + raise ValueError(error_msg) + + # 2) Request Keystone token + token_url = ( + "https://api-identity-infrastructure.nhncloudservice.com/v2.0/tokens" + ) + data = { + "auth": { + "tenantId": tenant_id, + "passwordCredentials": { + "username": username, + "password": password, + }, + } + } + resp = requests.post(token_url, json=data, timeout=10) + if resp.status_code != 200: + # Fail + error_msg = f"Failed to get token. Status: {resp.status_code}, Body: {resp.text}" + logger.error(error_msg) + if raise_on_exception: + raise Exception(error_msg) + return Connection(error=Exception(error_msg)) + + # Success + token_json = resp.json() + keystone_token = token_json["access"]["token"]["id"] + logger.info("NHN test_connection: Successfully acquired Keystone token.") + + # 3) (Optional) Test API call to confirm credentials are valid + compute_endpoint = f"https://kr1-api-instance.infrastructure.cloud.toast.com/v2/{tenant_id}" + + # Check servers list + headers = { + "X-Auth-Token": keystone_token, + "Content-Type": "application/json", + } + servers_resp = requests.get( + f"{compute_endpoint}/servers", headers=headers, timeout=10 + ) + if servers_resp.status_code == 200: + logger.info( + "NHN test_connection: /servers call success. Credentials valid." + ) + return Connection(is_connected=True) + else: + error_msg = f"/servers call failed. Status: {servers_resp.status_code}, Body: {servers_resp.text}" + logger.error(error_msg) + if raise_on_exception: + raise Exception(error_msg) + return Connection(error=Exception(error_msg)) + + except Exception as e: + logger.critical(f"{e.__class__.__name__}[{e.__traceback__.tb_lineno}]: {e}") + if raise_on_exception: + raise e + return Connection(error=e) diff --git a/prowler/providers/nhn/services/compute/__init__.py b/prowler/providers/nhn/services/compute/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/compute/compute_client.py b/prowler/providers/nhn/services/compute/compute_client.py new file mode 100644 index 0000000000..cf4bc98df0 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.nhn.services.compute.compute_service import NHNComputeService + +compute_client = NHNComputeService(Provider.get_global_provider()) diff --git a/prowler/providers/nhn/services/compute/compute_instance_login_user/__init__.py b/prowler/providers/nhn/services/compute/compute_instance_login_user/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.metadata.json b/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.metadata.json new file mode 100644 index 0000000000..535597bf39 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "compute_instance_login_user", + "CheckTitle": "Check for Administrative Login Users in NHN Compute Instances", + "CheckType": [], + "ServiceName": "compute", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "VMInstance", + "Description": "Checks if NHN Compute instances have administrative login users.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Review the login users configured for each VM instance.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.py b/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.py new file mode 100644 index 0000000000..95f575f83c --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user.py @@ -0,0 +1,22 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.compute.compute_client import compute_client + + +class compute_instance_login_user(Check): + def execute(self): + findings = [] + for instance in compute_client.instances: + report = CheckReportNHN( + metadata=self.metadata(), + resource=instance, + ) + report.status = "PASS" + report.status_extended = ( + f"VM Instance {instance.name} has a appropriate login user." + ) + if instance.login_user: + report.status = "FAIL" + report.status_extended = f"VM Instance {instance.name} has an Administrative(admin/root) login user." + findings.append(report) + + return findings diff --git a/prowler/providers/nhn/services/compute/compute_instance_public_ip/__init__.py b/prowler/providers/nhn/services/compute/compute_instance_public_ip/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.metadata.json b/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.metadata.json new file mode 100644 index 0000000000..b643fc5c60 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "compute_instance_public_ip", + "CheckTitle": "Check for Public IP in NHN Compute Instances", + "CheckType": [], + "ServiceName": "compute", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "low", + "ResourceType": "VMInstance", + "Description": "Check if a floating(public) IP is assigned to an NHN compute instance.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Remove or unassign floating IP if not required to reduce external exposure.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.py b/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.py new file mode 100644 index 0000000000..1a02dee8c8 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip.py @@ -0,0 +1,22 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.compute.compute_client import compute_client + + +class compute_instance_public_ip(Check): + def execute(self): + findings = [] + for instance in compute_client.instances: + report = CheckReportNHN( + metadata=self.metadata(), + resource=instance, + ) + report.status = "PASS" + report.status_extended = ( + f"VM Instance {instance.name} does not have a public IP." + ) + if instance.public_ip: + report.status = "FAIL" + report.status_extended = f"VM Instance {instance.name} has a public IP." + findings.append(report) + + return findings diff --git a/prowler/providers/nhn/services/compute/compute_instance_security_groups/__init__.py b/prowler/providers/nhn/services/compute/compute_instance_security_groups/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.metadata.json b/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.metadata.json new file mode 100644 index 0000000000..22ec845232 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "compute_instance_security_groups", + "CheckTitle": "Check NHN Compute Security Group Configuration", + "CheckType": [], + "ServiceName": "compute", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "VMInstance", + "Description": "Checks if NHN Compute VM instances are using appropriate security group configurations. Using only the default security group can pose a security risk.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Review and modify security group rules for each VM instance.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.py b/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.py new file mode 100644 index 0000000000..a6fb3073f4 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_instance_security_groups/compute_instance_security_groups.py @@ -0,0 +1,24 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.compute.compute_client import compute_client + + +class compute_instance_security_groups(Check): + def execute(self): + findings = [] + for instance in compute_client.instances: + report = CheckReportNHN( + metadata=self.metadata(), + resource=instance, + ) + report.status = "PASS" + report.status_extended = ( + f"VM Instance {instance.name} has a variety of security groups." + ) + if instance.security_groups: + report.status = "FAIL" + report.status_extended = ( + f"VM Instance {instance.name} has only the default security group." + ) + findings.append(report) + + return findings diff --git a/prowler/providers/nhn/services/compute/compute_service.py b/prowler/providers/nhn/services/compute/compute_service.py new file mode 100644 index 0000000000..082c04bc96 --- /dev/null +++ b/prowler/providers/nhn/services/compute/compute_service.py @@ -0,0 +1,95 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.nhn.nhn_provider import NhnProvider + + +class NHNComputeService: + def __init__(self, provider: NhnProvider): + self.session = provider.session + self.tenant_id = provider._tenant_id + self.endpoint = "https://kr1-api-instance.infrastructure.cloud.toast.com" + + self.instances: list[Instance] = [] + self._get_instances() + + def _list_servers(self) -> list: + url = f"{self.endpoint}/v2/{self.tenant_id}/servers" + try: + response = self.session.get(url, timeout=10) + response.raise_for_status() + data = response.json() + return data.get("servers", []) + except Exception as e: + logger.error(f"Error listing servers: {e}") + return [] + + def _get_server_detail(self, server_id: str) -> dict: + url = f"{self.endpoint}/v2/{self.tenant_id}/servers/{server_id}" + try: + response = self.session.get(url, timeout=10) + response.raise_for_status() + return response.json() + except Exception as e: + logger.error(f"Error getting server detail {server_id}: {e}") + return {} + + def _check_public_ip(self, server_info: dict) -> bool: + addresses = server_info.get("addresses", {}) + for _, ip_list in addresses.items(): + for ip_info in ip_list: + if ip_info.get("OS-EXT-IPS:type") == "floating": + return True + return False + + def _check_security_groups(self, server_info: dict) -> bool: + secruity_groups = server_info.get("security_groups", []) + sg_names = [] + for sg_info in secruity_groups: + name = sg_info.get("name", "") + sg_names.append(name) + + for name in sg_names: + if name != "default": + return False + return True + + def _check_login_user(self, server_info: dict) -> bool: + metadata = server_info.get("metadata", {}) + login_user = metadata.get("login_username", "") + if ( + login_user == "Administrator" + or login_user == "root" + or login_user == "admin" + ): + return True + return False + + def _get_instances(self): + server_list = self._list_servers() + for server in server_list: + server_id = server["id"] + server_name = server["name"] + detail = self._get_server_detail(server_id) + server_info = detail.get("server", {}) + + server_public_ip = self._check_public_ip(server_info) + server_security_groups = self._check_security_groups(server_info) + server_login_user = self._check_login_user(server_info) + + instance = Instance( + id=server_id, + name=server_name, + public_ip=server_public_ip, + security_groups=server_security_groups, + login_user=server_login_user, + ) + self.instances.append(instance) + + +class Instance(BaseModel): + id: str + name: str + public_ip: bool + security_groups: bool + login_user: bool diff --git a/prowler/providers/nhn/services/network/__init__.py b/prowler/providers/nhn/services/network/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/network/network_client.py b/prowler/providers/nhn/services/network/network_client.py new file mode 100644 index 0000000000..9c53cfd3ba --- /dev/null +++ b/prowler/providers/nhn/services/network/network_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.nhn.services.network.network_service import NHNNetworkService + +network_client = NHNNetworkService(Provider.get_global_provider()) diff --git a/prowler/providers/nhn/services/network/network_service.py b/prowler/providers/nhn/services/network/network_service.py new file mode 100644 index 0000000000..140e1d2815 --- /dev/null +++ b/prowler/providers/nhn/services/network/network_service.py @@ -0,0 +1,89 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.nhn.nhn_provider import NhnProvider + + +class Subnet(BaseModel): + name: str + external_router: bool + enable_dhcp: bool + + +class Network(BaseModel): + id: str + name: str + empty_routingtables: bool + subnets: list[Subnet] + + +class NHNNetworkService: + def __init__(self, provider: NhnProvider): + self.session = provider.session + self.tenant_id = provider._tenant_id + self.endpoint = "https://kr1-api-network-infrastructure.nhncloudservice.com" + self.networks: list[Network] = [] + self._get_networks() + + def _list_vpcs(self) -> list: + url = f"{self.endpoint}/v2.0/vpcs" + try: + response = self.session.get(url, timeout=10) + response.raise_for_status() + data = response.json() + return data.get("vpcs", []) + except Exception as e: + logger.error(f"Error listing vpcs: {e}") + return [] + + def _get_vpc_detail(self, vpc_id: str) -> dict: + url = f"{self.endpoint}/v2.0/vpcs/{vpc_id}" + try: + response = self.session.get(url, timeout=10) + response.raise_for_status() + return response.json() + except Exception as e: + logger.error(f"Error getting vpc detail {vpc_id}: {e}") + return {} + + def _check_has_empty_routingtables(self, vpc_info: dict) -> bool: + routingtables = vpc_info.get("routingtables", []) + return not routingtables + + def _check_subnet_has_external_router(self, subnet: dict) -> bool: + return subnet.get("router:external", True) + + def _check_subnet_enable_dhcp(self, subnet: dict) -> bool: + return subnet.get("enable_dhcp", True) + + def _get_networks(self): + vpc_list = self._list_vpcs() + for vpc in vpc_list: + vpc_id = vpc["id"] + vpc_name = vpc["name"] + detail = self._get_vpc_detail(vpc_id) + vpc_info = detail.get("vpc", {}) + vpc_empty_routingtables = self._check_has_empty_routingtables(vpc_info) + + network = Network( + id=vpc_id, + name=vpc_name, + empty_routingtables=vpc_empty_routingtables, + subnets=[], + ) + self._get_subnets(vpc_info, network) + self.networks.append(network) + + def _get_subnets(self, vpc_info: dict, network: Network): + subnet_list = vpc_info.get("subnets", []) + # ret_subnet_list = [] + for subnet in subnet_list: + subnet_name = subnet["name"] + subnet_external_router = self._check_subnet_has_external_router(subnet) + subnet_enable_dhcp = self._check_subnet_enable_dhcp(subnet) + subnet_instance = Subnet( + name=subnet_name, + external_router=subnet_external_router, + enable_dhcp=subnet_enable_dhcp, + ) + network.subnets.append(subnet_instance) diff --git a/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/__init__.py b/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.metadata.json b/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.metadata.json new file mode 100644 index 0000000000..8ded29ecb6 --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "network_vpc_has_empty_routingtables", + "CheckTitle": "Check if VPC has empty routing tables", + "CheckType": [], + "ServiceName": "network", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "VPC", + "Description": "Check if VPC has empty routing tables. Having empty routing tables may indicate misconfiguration or incomplete network setup.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that VPC has properly configured routing tables with necessary routes to ensure proper network connectivity. If not needed, delete the empty routing tables.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.py b/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.py new file mode 100644 index 0000000000..fd3051445a --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables.py @@ -0,0 +1,22 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.network.network_client import network_client + + +class network_vpc_has_empty_routingtables(Check): + def execute(self): + findings = [] + for network in network_client.networks: + report = CheckReportNHN( + metadata=self.metadata(), + resource=network, + ) + report.status = "PASS" + report.status_extended = ( + f"VPC {network.name} does not have empty routingtables." + ) + if network.empty_routingtables: + report.status = "FAIL" + report.status_extended = f"VPC {network.name} has empty routingtables." + findings.append(report) + + return findings diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/__init__.py b/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.metadata.json b/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.metadata.json new file mode 100644 index 0000000000..c13f16cb25 --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "network_vpc_subnet_enable_dhcp", + "CheckTitle": "Check if DHCP is enabled for subnets in VPC", + "CheckType": [], + "ServiceName": "network", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "VPC", + "Description": "Check if DHCP is enabled for the subnets in the VPC.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that DHCP is enabled for all subnets where automatic IP address allocation is needed.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.py b/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.py new file mode 100644 index 0000000000..c90c71b8fd --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.network.network_client import network_client + + +class network_vpc_subnet_enable_dhcp(Check): + def execute(self): + findings = [] + for network in network_client.networks: + for subnet in network.subnets: + report = CheckReportNHN( + metadata=self.metadata(), + resource=network, + ) + report.status = "PASS" + report.status_extended = f"VPC {network.name} Subnet {subnet.name} does not have DHCP enabled." + if subnet.enable_dhcp: + report.status = "FAIL" + report.status_extended = ( + f"VPC {network.name} Subnet {subnet.name} has DHCP enabled." + ) + findings.append(report) + + return findings diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/__init__.py b/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.metadata.json b/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.metadata.json new file mode 100644 index 0000000000..4a975d0ed7 --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "nhn", + "CheckID": "network_vpc_subnet_has_external_router", + "CheckTitle": "Check for External Router in NHN VPC Subnet", + "CheckType": [], + "ServiceName": "network", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "VPC", + "Description": "Checks if VPC allows access from the public internet, by verifying if an external router is configured.", + "Risk": "", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Review the external router settings for the VPC Subnet.", + "Url": "" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.py b/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.py new file mode 100644 index 0000000000..c8c7f42d64 --- /dev/null +++ b/prowler/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router.py @@ -0,0 +1,21 @@ +from prowler.lib.check.models import Check, CheckReportNHN +from prowler.providers.nhn.services.network.network_client import network_client + + +class network_vpc_subnet_has_external_router(Check): + def execute(self): + findings = [] + for network in network_client.networks: + for subnet in network.subnets: + report = CheckReportNHN( + metadata=self.metadata(), + resource=network, + ) + report.status = "PASS" + report.status_extended = f"VPC {network.name} Subnet {subnet.name} does not have an external router." + if subnet.external_router: + report.status = "FAIL" + report.status_extended = f"VPC {network.name} Subnet {subnet.name} has an external router." + findings.append(report) + + return findings diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index 16b322ac9c..37bec15d94 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -16,11 +16,11 @@ prowler_command = "prowler" # capsys # https://docs.pytest.org/en/7.1.x/how-to/capture-stdout-stderr.html -prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,dashboard} ..." +prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,nhn,dashboard} ..." def mock_get_available_providers(): - return ["aws", "azure", "gcp", "kubernetes", "microsoft365"] + return ["aws", "azure", "gcp", "kubernetes", "microsoft365", "nhn"] @pytest.mark.arg_parser diff --git a/tests/providers/nhn/lib/mutelist/fixtures/nhn_mutelist.yaml b/tests/providers/nhn/lib/mutelist/fixtures/nhn_mutelist.yaml new file mode 100644 index 0000000000..6a4be42b4b --- /dev/null +++ b/tests/providers/nhn/lib/mutelist/fixtures/nhn_mutelist.yaml @@ -0,0 +1,16 @@ +### Account, Check and/or Region can be * to apply for all the cases. +### Resources and tags are lists that can have either Regex or Keywords. +### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together. +### Use an alternation Regex to match one of multiple tags with "ORed" logic. +### For each check you can except Accounts, Regions, Resources and/or Tags. +########################### MUTELIST EXAMPLE ########################### +Mutelist: + Accounts: + "subscription_1": + Checks: + "compute_instance_public_ip": + Regions: + - "*" + Resources: + - "resource_1" + - "resource_2" \ No newline at end of file diff --git a/tests/providers/nhn/lib/mutelist/nhn_mutelist_test.py b/tests/providers/nhn/lib/mutelist/nhn_mutelist_test.py new file mode 100644 index 0000000000..dcdc17b2d9 --- /dev/null +++ b/tests/providers/nhn/lib/mutelist/nhn_mutelist_test.py @@ -0,0 +1,100 @@ +import yaml +from mock import MagicMock + +from prowler.providers.nhn.lib.mutelist.mutelist import NHNMutelist +from tests.lib.outputs.fixtures.fixtures import generate_finding_output + +MUTELIST_FIXTURE_PATH = "tests/providers/nhn/lib/mutelist/fixtures/nhn_mutelist.yaml" + + +class TestNHNMutelist: + def test_get_mutelist_file_from_local_file(self): + mutelist = NHNMutelist(mutelist_path=MUTELIST_FIXTURE_PATH) + + with open(MUTELIST_FIXTURE_PATH) as f: + mutelist_fixture = yaml.safe_load(f)["Mutelist"] + + assert mutelist.mutelist == mutelist_fixture + assert mutelist.mutelist_file_path == MUTELIST_FIXTURE_PATH + + def test_get_mutelist_file_from_local_file_non_existent(self): + mutelist_path = "tests/lib/mutelist/fixtures/not_present" + mutelist = NHNMutelist(mutelist_path=mutelist_path) + + assert mutelist.mutelist == {} + assert mutelist.mutelist_file_path == mutelist_path + + def test_validate_mutelist_not_valid_key(self): + mutelist_path = MUTELIST_FIXTURE_PATH + with open(mutelist_path) as f: + mutelist_fixture = yaml.safe_load(f)["Mutelist"] + + mutelist_fixture["Accounts1"] = mutelist_fixture["Accounts"] + del mutelist_fixture["Accounts"] + + mutelist = NHNMutelist(mutelist_content=mutelist_fixture) + + assert not mutelist.validate_mutelist() + assert mutelist.mutelist == {} + assert mutelist.mutelist_file_path is None + + def test_is_finding_muted(self): + # Mutelist + mutelist_content = { + "Accounts": { + "resource_1": { + "Checks": { + "check_test": { + "Regions": ["*"], + "Resources": ["test_resource"], + } + } + } + } + } + + mutelist = NHNMutelist(mutelist_content=mutelist_content) + + finding = MagicMock() + finding.resource_id = "resource_1" + finding.check_metadata = MagicMock() + finding.check_metadata.CheckID = "check_test" + finding.status = "FAIL" + finding.resource_name = "test_resource" + finding.location = "test_region" + finding.resource_tags = [] + + assert mutelist.is_finding_muted(finding) + + def test_mute_finding(self): + # Mutelist + mutelist_content = { + "Accounts": { + "resource_1": { + "Checks": { + "check_test": { + "Regions": ["*"], + "Resources": ["test_resource"], + } + } + } + } + } + + mutelist = NHNMutelist(mutelist_content=mutelist_content) + + finding_1 = generate_finding_output( + check_id="check_test", + status="FAIL", + account_uid="resource_1", + region="test_region", + resource_uid="test_resource", + resource_tags=[], + muted=False, + ) + + muted_finding = mutelist.mute_finding(finding=finding_1) + + assert muted_finding.status == "MUTED" + assert muted_finding.muted + assert muted_finding.raw["status"] == "FAIL" diff --git a/tests/providers/nhn/nhn_fixtures.py b/tests/providers/nhn/nhn_fixtures.py new file mode 100644 index 0000000000..a8a1fbd53e --- /dev/null +++ b/tests/providers/nhn/nhn_fixtures.py @@ -0,0 +1,29 @@ +from mock import MagicMock + +from prowler.providers.nhn.nhn_provider import NhnProvider + + +def set_mocked_nhn_provider( + username="test_user", + password="test_password", + tenant_id="tenant123", + audit_config=None, + fixer_config=None, +): + """ + Creates a mocked NHN Provider object for testing without real network calls. + """ + provider = MagicMock(spec=NhnProvider) # or just MagicMock() + + provider.type = "nhn" + provider._username = username + provider._password = password + provider._tenant_id = tenant_id + provider._token = "fake_keystone_token" + + provider.session = MagicMock() + + provider.audit_config = audit_config + provider.fixer_config = fixer_config + + return provider diff --git a/tests/providers/nhn/nhn_provider_test.py b/tests/providers/nhn/nhn_provider_test.py new file mode 100644 index 0000000000..dc59ac1347 --- /dev/null +++ b/tests/providers/nhn/nhn_provider_test.py @@ -0,0 +1,157 @@ +import os +from unittest.mock import MagicMock, patch + +import pytest + +from prowler.providers.common.models import Connection +from prowler.providers.nhn.nhn_provider import NhnProvider + + +class TestNhnProvider: + @patch.dict( + os.environ, + { + "NHN_USERNAME": "env_user", + "NHN_PASSWORD": "env_pass", + "NHN_TENANT_ID": "env_tenant", + }, + ) + @patch("prowler.providers.nhn.nhn_provider.load_and_validate_config_file") + @patch("requests.post") + def test_nhn_provider_init_success(self, mock_post, mock_load_config): + """ + Test a successful initialization of NhnProvider + with valid username/password/tenant_id and a Keystone token response = 200. + """ + # 1) Mock load_and_validate_config_file to avoid reading real config file + mock_load_config.return_value = {} + + # 2) Mock the requests.post to simulate a successful token response + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "access": {"token": {"id": "fake_keystone_token"}} + } + mock_post.return_value = mock_response + + # 3) Create provider + provider = NhnProvider( + username="test_user", + password="test_pass", + tenant_id="test_tenant", + ) + + # 4) Assertions + assert provider._token == "fake_keystone_token" + assert provider.session is not None + assert provider.session.headers["X-Auth-Token"] == "fake_keystone_token" + + @patch.dict(os.environ, {}, clear=True) + @patch( + "prowler.providers.nhn.nhn_provider.load_and_validate_config_file", + return_value={}, + ) + def test_nhn_provider_init_missing_args(self, mock_load_config): + """ + Test initialization when username/password/tenant_id is missing => ValueError + """ + with pytest.raises(ValueError) as exc_info: + NhnProvider(username="", password="secret", tenant_id="tenant") + assert "requires username, password and tenant_id" in str(exc_info.value) + + @patch( + "prowler.providers.nhn.nhn_provider.load_and_validate_config_file", + return_value={}, + ) + @patch("requests.post") + def test_nhn_provider_init_token_fail(self, mock_post, mock_load_config): + """ + Test the case where Keystone token request fails (non-200) + => provider._session remains None + """ + mock_post.return_value.status_code = 401 + mock_post.return_value.text = "Unauthorized" + + with pytest.raises(ValueError) as exc_info: + NhnProvider( + username="test_user", + password="test_pass", + tenant_id="tenant123", + ) + + assert "Failed to get NHN token" in str(exc_info.value) + + @patch("prowler.providers.nhn.nhn_provider.requests") + def test_test_connection_success(self, mock_requests): + """ + Test test_connection static method => success case + """ + # 1) Mock token success + mock_post_response = MagicMock() + mock_post_response.status_code = 200 + mock_post_response.json.return_value = { + "access": {"token": {"id": "fake_keystone_token"}} + } + # 2) Mock /servers success + mock_get_response = MagicMock() + mock_get_response.status_code = 200 + mock_requests.post.return_value = mock_post_response + mock_requests.get.return_value = mock_get_response + + conn = NhnProvider.test_connection( + username="test_user", + password="test_pass", + tenant_id="tenant123", + raise_on_exception=True, + ) + + assert isinstance(conn, Connection) + assert conn.is_connected is True + assert conn.error is None + + @patch("prowler.providers.nhn.nhn_provider.requests") + def test_test_connection_token_fail(self, mock_requests): + """ + Test test_connection => token request fails => returns Connection(error=...) + """ + mock_requests.post.return_value.status_code = 403 + mock_requests.post.return_value.text = "Forbidden" + + conn = NhnProvider.test_connection( + username="bad_user", + password="bad_pass", + tenant_id="tenant123", + raise_on_exception=False, # so we don't raise, we get Connection object + ) + assert conn.is_connected is False + assert conn.error is not None + assert "Failed to get token" in str(conn.error) + + @patch("prowler.providers.nhn.nhn_provider.requests") + def test_test_connection_servers_fail(self, mock_requests): + """ + Test test_connection => token OK, but /servers fails => returns Connection(error=...) + """ + # Keystone token success + mock_post_response = MagicMock() + mock_post_response.status_code = 200 + mock_post_response.json.return_value = { + "access": {"token": {"id": "fake_keystone_token"}} + } + mock_requests.post.return_value = mock_post_response + + # /servers fail + mock_get_response = MagicMock() + mock_get_response.status_code = 500 + mock_get_response.text = "Internal Server Error" + mock_requests.get.return_value = mock_get_response + + conn = NhnProvider.test_connection( + username="test_user", + password="test_pass", + tenant_id="tenant123", + raise_on_exception=False, + ) + assert conn.is_connected is False + assert conn.error is not None + assert "/servers call failed" in str(conn.error) diff --git a/tests/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user_test_for_nhn.py b/tests/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user_test_for_nhn.py new file mode 100644 index 0000000000..5e545d87c3 --- /dev/null +++ b/tests/providers/nhn/services/compute/compute_instance_login_user/compute_instance_login_user_test_for_nhn.py @@ -0,0 +1,110 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.compute.compute_service import Instance +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_compute_instance_login_user: + def test_no_instances(self): + # 1) Make a MagicMock for compute_client + compute_client = mock.MagicMock() + compute_client.instances = [] + + # 2) Patch get_global_provider() to return a mocked NHN provider + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + # patch the 'compute_instance_login_user.compute_client' used in the check code + "prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user.compute_client", + new=compute_client, + ), + ): + # 3) Import the check code AFTER patching + from prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user import ( + compute_instance_login_user, + ) + + # 4) Run the check + check = compute_instance_login_user() + result = check.execute() + + # 5) Assertions + assert len(result) == 0 # no instances => no findings + + def test_has_instance_non_admin_login(self): + # Make a MagicMock for compute_client + compute_client = mock.MagicMock() + + # Suppose we have 1 instance with login_user=False => PASS expected + instance_id = str(uuid4()) + instance_name = "testVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.login_user = False # => means not admin login + compute_client.instances = [mock_instance] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user import ( + compute_instance_login_user, + ) + + check = compute_instance_login_user() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "has a appropriate login user" in result[0].status_extended + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id + + def test_has_instance_admin_login(self): + # Another scenario: instance with login_user=True => FAIL expected + compute_client = mock.MagicMock() + + instance_id = str(uuid4()) + instance_name = "rootVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.login_user = True # => admin or root user + compute_client.instances = [mock_instance] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_login_user.compute_instance_login_user import ( + compute_instance_login_user, + ) + + check = compute_instance_login_user() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + "has an Administrative(admin/root) login user" + in result[0].status_extended + ) + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id diff --git a/tests/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip_test_for_nhn.py b/tests/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip_test_for_nhn.py new file mode 100644 index 0000000000..2b72460c78 --- /dev/null +++ b/tests/providers/nhn/services/compute/compute_instance_public_ip/compute_instance_public_ip_test_for_nhn.py @@ -0,0 +1,107 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.compute.compute_service import Instance +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_compute_instance_public_ip: + def test_no_instances(self): + # 1) Make a MagicMock for compute_client + compute_client = mock.MagicMock() + compute_client.instances = [] + + # 2) Patch get_global_provider() to return a mocked NHN provider + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + # patch the 'compute_instance_public_ip.compute_client' used in the check code + "prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip.compute_client", + new=compute_client, + ), + ): + # 3) Import the check code AFTER patching + from prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip import ( + compute_instance_public_ip, + ) + + # 4) Run the check + check = compute_instance_public_ip() + result = check.execute() + + # 5) Assertions + assert len(result) == 0 # no instances => no findings + + def test_has_instance_non_public_ip(self): + # Make a MagicMock for compute_client + compute_client = mock.MagicMock() + + # Suppose we have 1 instance with public_ip=False => PASS expected + instance_id = str(uuid4()) + instance_name = "testVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.public_ip = False # => means does not have public IP + compute_client.instances = [mock_instance] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip import ( + compute_instance_public_ip, + ) + + check = compute_instance_public_ip() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "does not have a public IP" in result[0].status_extended + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id + + def test_has_instance_public_ip(self): + # Another scenario: instance with public_ip=True => FAIL expected + compute_client = mock.MagicMock() + + instance_id = str(uuid4()) + instance_name = "rootVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.public_ip = True # => means has public IP + compute_client.instances = [mock_instance] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_public_ip.compute_instance_public_ip import ( + compute_instance_public_ip, + ) + + check = compute_instance_public_ip() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "has a public IP" in result[0].status_extended + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id diff --git a/tests/providers/nhn/services/compute/compute_instance_security__groups/compute_instance_security_groups_test_for_nhn.py b/tests/providers/nhn/services/compute/compute_instance_security__groups/compute_instance_security_groups_test_for_nhn.py new file mode 100644 index 0000000000..194c80be2c --- /dev/null +++ b/tests/providers/nhn/services/compute/compute_instance_security__groups/compute_instance_security_groups_test_for_nhn.py @@ -0,0 +1,108 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.compute.compute_service import Instance +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_compute_instance_security_groups: + def test_no_instances(self): + # 1) Make a MagicMock for compute_client + compute_client = mock.MagicMock() + compute_client.instances = [] + + # 2) Patch get_global_provider() to return a mocked NHN provider + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + # patch the 'compute_instance_security_groups.compute_client' used in the check code + "prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups.compute_client", + new=compute_client, + ), + ): + # 3) Import the check code AFTER patching + from prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups import ( + compute_instance_security_groups, + ) + + # 4) Run the check + check = compute_instance_security_groups() + result = check.execute() + + # 5) Assertions + assert len(result) == 0 # no instances => no findings + + def test_has_instance_variety_security_groups(self): + # Make a MagicMock for compute_client + compute_client = mock.MagicMock() + + # Suppose we have 1 instance with security_groups=False => PASS expected + instance_id = str(uuid4()) + instance_name = "testVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.security_groups = False # => means has variety of security groups + compute_client.instances = [mock_instance] + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups import ( + compute_instance_security_groups, + ) + + check = compute_instance_security_groups() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "has a variety of security groups" in result[0].status_extended + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id + + def test_has_instance_security_groups(self): + # Another scenario: instance with security_groups=True => FAIL expected + compute_client = mock.MagicMock() + + instance_id = str(uuid4()) + instance_name = "rootVM" + mock_instance = mock.MagicMock(spec=Instance) + mock_instance.id = instance_id + mock_instance.name = instance_name + mock_instance.security_groups = ( + True # => means has only the default security group + ) + compute_client.instances = [mock_instance] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups.compute_client", + new=compute_client, + ), + ): + from prowler.providers.nhn.services.compute.compute_instance_security_groups.compute_instance_security_groups import ( + compute_instance_security_groups, + ) + + check = compute_instance_security_groups() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "has only the default security group" in result[0].status_extended + assert result[0].resource_name == instance_name + assert result[0].resource_id == instance_id diff --git a/tests/providers/nhn/services/compute/compute_service_test_for_nhn.py b/tests/providers/nhn/services/compute/compute_service_test_for_nhn.py new file mode 100644 index 0000000000..d5a8726b8d --- /dev/null +++ b/tests/providers/nhn/services/compute/compute_service_test_for_nhn.py @@ -0,0 +1,100 @@ +from unittest.mock import MagicMock, patch + +from prowler.providers.nhn.services.compute.compute_service import NHNComputeService +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class TestNHNComputeService: + @patch("prowler.providers.nhn.services.compute.compute_service.logger") + def test_compute_service_basic(self, mock_logger): + """ + Test that NHNComputeService properly calls _list_servers(), + _get_server_detail() for each server, and populates self.instances. + """ + # create a mocked NHN Provider + provider = set_mocked_nhn_provider( + username="testUser", + password="testPass", + tenant_id="tenant123", + ) + + # define mocked responses + mocked_response_servers = MagicMock() + mocked_response_servers.status_code = 200 + mocked_response_servers.json.return_value = { + "servers": [ + {"id": "server1", "name": "myserver1"}, + {"id": "server2", "name": "myserver2"}, + ] + } + + mocked_response_server1 = MagicMock() + mocked_response_server1.status_code = 200 + mocked_response_server1.json.return_value = { + "server": { + "addresses": { + "vpc1": [ + {"OS-EXT-IPS:type": "floating"}, + ] + }, + "security_groups": [{"name": "default"}], + "metadata": {"login_username": "root"}, + } + } + + mocked_response_server2 = MagicMock() + mocked_response_server2.status_code = 200 + mocked_response_server2.json.return_value = { + "server": { + "addresses": { + "vpc1": [ + {"OS-EXT-IPS:type": "fixed"}, + ] + }, + "security_groups": [{"name": "default"}, {"name": "other-sg"}], + "metadata": {"login_username": "regularuser"}, + } + } + + def get_side_effect(url, timeout=10): + print(f"Called with timeout={timeout}") + if ( + "/v2/tenant123/servers" in url + and not url.endswith("server1") + and not url.endswith("server2") + ): + return mocked_response_servers + elif url.endswith("server1"): + return mocked_response_server1 + elif url.endswith("server2"): + return mocked_response_server2 + else: + mock_404 = MagicMock() + mock_404.status_code = 404 + mock_404.text = "Not Found" + return mock_404 + + provider.session.get.side_effect = get_side_effect + + # create NHNComputeService, which internally calls _get_instances() + compute_service = NHNComputeService(provider) + + assert len(compute_service.instances) == 2 + + # first instance + inst1 = compute_service.instances[0] + assert inst1.id == "server1" + assert inst1.name == "myserver1" + assert inst1.public_ip is True + assert inst1.security_groups is True + assert inst1.login_user is True + + # second instance + inst2 = compute_service.instances[1] + assert inst2.id == "server2" + assert inst2.name == "myserver2" + assert inst2.public_ip is False + assert inst2.security_groups is False + assert inst2.login_user is False + + mock_logger.error.assert_not_called() diff --git a/tests/providers/nhn/services/network/network_service_test_for_nhn.py b/tests/providers/nhn/services/network/network_service_test_for_nhn.py new file mode 100644 index 0000000000..ca781e8e75 --- /dev/null +++ b/tests/providers/nhn/services/network/network_service_test_for_nhn.py @@ -0,0 +1,98 @@ +from unittest.mock import MagicMock, patch + +from prowler.providers.nhn.services.network.network_service import NHNNetworkService +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class TestNHNNetworkService: + @patch("prowler.providers.nhn.services.network.network_service.logger") + def test_network_service_basic(self, mock_logger): + """ + Test that NHNNetworkService correctly calls _list_vpcs(), + _get_vpc_detail() for each VPC, and populates self.networks and self.subnets. + """ + # create a mocked NHN Provider + provider = set_mocked_nhn_provider( + username="testUser", + password="testPass", + tenant_id="tenant123", + ) + + # define mocked responses for VPCs and Subnets + mocked_response_vpcs = MagicMock() + mocked_response_vpcs.status_code = 200 + mocked_response_vpcs.json.return_value = { + "vpcs": [ + {"id": "vpc1", "name": "myvpc1"}, + {"id": "vpc2", "name": "myvpc2"}, + ] + } + + mocked_response_vpc1 = MagicMock() + mocked_response_vpc1.status_code = 200 + mocked_response_vpc1.json.return_value = { + "vpc": { + "routingtables": [], + "subnets": [ + {"name": "subnet1", "router:external": True, "enable_dhcp": False}, + ], + } + } + + mocked_response_vpc2 = MagicMock() + mocked_response_vpc2.status_code = 200 + mocked_response_vpc2.json.return_value = { + "vpc": { + "routingtables": [{"id": "rt1"}], + "subnets": [ + {"name": "subnet2", "router:external": False, "enable_dhcp": True}, + ], + } + } + + def get_side_effect(url, timeout=10): + print(f"Called with timeout={timeout}") + if ( + "/v2.0/vpcs" in url + and not url.endswith("vpc1") + and not url.endswith("vpc2") + ): + return mocked_response_vpcs + elif url.endswith("vpc1"): + return mocked_response_vpc1 + elif url.endswith("vpc2"): + return mocked_response_vpc2 + else: + mock_404 = MagicMock() + mock_404.status_code = 404 + mock_404.text = "Not Found" + return mock_404 + + provider.session.get.side_effect = get_side_effect + + # create NHNNetworkService, which internally calls _get_networks() and _get_subnets() + network_service = NHNNetworkService(provider) + + assert len(network_service.networks) == 2 + + # first network + net1 = network_service.networks[0] + assert net1.id == "vpc1" + assert net1.name == "myvpc1" + assert net1.empty_routingtables is True + assert len(net1.subnets) == 1 + assert net1.subnets[0].name == "subnet1" + assert net1.subnets[0].external_router is True + assert net1.subnets[0].enable_dhcp is False + + # second network + net2 = network_service.networks[1] + assert net2.id == "vpc2" + assert net2.name == "myvpc2" + assert net2.empty_routingtables is False # Assuming there's a routing table + assert len(net2.subnets) == 1 + assert net2.subnets[0].name == "subnet2" + assert net2.subnets[0].external_router is False + assert net2.subnets[0].enable_dhcp is True + + mock_logger.error.assert_not_called() diff --git a/tests/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables_test_for_nhn.py b/tests/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables_test_for_nhn.py new file mode 100644 index 0000000000..3af49eb699 --- /dev/null +++ b/tests/providers/nhn/services/network/network_vpc_has_empty_routingtables/network_vpc_has_empty_routingtables_test_for_nhn.py @@ -0,0 +1,107 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.network.network_service import Network +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_vpc_has_empty_routingtables: + def test_no_networks(self): + # 1) Make a MagicMock for network_client + network_client = mock.MagicMock() + network_client.networks = [] + + # 2) Patch get_global_provider() to return a mocked NHN provider + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + # patch the 'network_empty_routingtables.network_client' used in the check code + "prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables.network_client", + new=network_client, + ), + ): + # 3) Import the check code AFTER patching + from prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables import ( + network_vpc_has_empty_routingtables, + ) + + # 4) Run the check + check = network_vpc_has_empty_routingtables() + result = check.execute() + + # 5) Assertions + assert len(result) == 0 # no networks => no findings + + def test_vpc_has_empty_routingtables(self): + # Make a MagicMock for network_client + network_client = mock.MagicMock() + + # Suppose we have 1 network with empty_routingtables=True => FAIL expected + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_network.empty_routingtables = True + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables import ( + network_vpc_has_empty_routingtables, + ) + + check = network_vpc_has_empty_routingtables() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "has empty routingtables" in result[0].status_extended + assert result[0].resource_name == network_name + assert result[0].resource_id == network_id + + def test_vpc_does_not_have_empty_routingtables(self): + # Another scenario: network with empty_routingtables=False => PASS expected + network_client = mock.MagicMock() + + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_network.empty_routingtables = False + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_has_empty_routingtables.network_vpc_has_empty_routingtables import ( + network_vpc_has_empty_routingtables, + ) + + check = network_vpc_has_empty_routingtables() + result = check.execute() + + assert len(result) == 0 + assert result[0].status == "PASS" + assert "dose not have empty routingtables" in result[0].status_extended + assert result[0].resource_name == network_name + assert result[0].resource_id == network_id diff --git a/tests/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp_for_nhn.py b/tests/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp_for_nhn.py new file mode 100644 index 0000000000..2c3c1cf722 --- /dev/null +++ b/tests/providers/nhn/services/network/network_vpc_subnet_enable_dhcp/network_vpc_subnet_enable_dhcp_for_nhn.py @@ -0,0 +1,113 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.network.network_service import Network, Subnet +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_network_vpc_subnet_enable_dhcp: + def test_no_networks(self): + # 1) Make a MagicMock for network_client + network_client = mock.MagicMock() + network_client.networks = [] + + # 2) Patch get_global_provider() to return a mocked NHN provider + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + # patch the 'network_vpc_subnet_enable_dhcp.network_client' used in the check code + "prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp.network_client", + new=network_client, + ), + ): + # 3) Import the check code AFTER patching + from prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp import ( + network_vpc_subnet_enable_dhcp, + ) + + # 4) Run the check + check = network_vpc_subnet_enable_dhcp() + result = check.execute() + + # 5) Assertions + assert len(result) == 0 # no networks => no findings + + def test_vpc_subnet_enable_dhcp(self): + # Make a MagicMock for network_client + network_client = mock.MagicMock() + + # Suppose we have 1 network with enable_dhcp=True => FAIL expected + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_subnet = mock.MagicMock(spec=Subnet) + mock_subnet.name = "subnet1" + mock_subnet.enable_dhcp = True + mock_network.subnets = [mock_subnet] + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp import ( + network_vpc_subnet_enable_dhcp, + ) + + check = network_vpc_subnet_enable_dhcp() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "has DHCP enabled" in result[0].status_extended + assert result[0].resource_name == network_name + assert result[0].resource_id == network_id + + def test_vpc_subnet_unable_dhcp(self): + # Another scenario: network with enable_dhcp=False => PASS expected + network_client = mock.MagicMock() + + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_subnet = mock.MagicMock(spec=Subnet) + mock_subnet.name = "subnet1" + mock_subnet.enable_dhcp = False + mock_network.subnets = [mock_subnet] + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_subnet_enable_dhcp.network_vpc_subnet_enable_dhcp import ( + network_vpc_subnet_enable_dhcp, + ) + + check = network_vpc_subnet_enable_dhcp() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "does not have DHCP enabled" in result[0].status_extended + assert result[0].resource_name == network_name + assert result[0].resource_id == network_id diff --git a/tests/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router_for_nhn.py b/tests/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router_for_nhn.py new file mode 100644 index 0000000000..ec45a22ecd --- /dev/null +++ b/tests/providers/nhn/services/network/network_vpc_subnet_has_external_router/network_vpc_subnet_has_external_router_for_nhn.py @@ -0,0 +1,104 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.nhn.services.network.network_service import Network, Subnet +from tests.providers.nhn.nhn_fixtures import set_mocked_nhn_provider + + +class Test_network_vpc_subnet_has_external_router: + def test_no_networks(self): + network_client = mock.MagicMock() + network_client.networks = [] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router import ( + network_vpc_subnet_has_external_router, + ) + + check = network_vpc_subnet_has_external_router() + result = check.execute() + + assert len(result) == 0 + + def test_vpc_subnet_has_external_router(self): + network_client = mock.MagicMock() + + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_subnet = mock.MagicMock(spec=Subnet) + mock_subnet.name = "subnet1" + mock_subnet.external_router = True + mock_network.subnets = [mock_subnet] + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router import ( + network_vpc_subnet_has_external_router, + ) + + check = network_vpc_subnet_has_external_router() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "has external router" in result[0].status_extended + assert result[0].resource_id == network_id + assert result[0].resource_name == network_name + + def test_vpc_subnet_no_external_router(self): + network_client = mock.MagicMock() + + network_id = str(uuid4()) + network_name = "testNetwork" + mock_network = mock.MagicMock(spec=Network) + mock_network.id = network_id + mock_network.name = network_name + mock_subnet = mock.MagicMock(spec=Subnet) + mock_subnet.name = "subnet1" + mock_subnet.external_router = False + mock_network.subnets = [mock_subnet] + network_client.networks = [mock_network] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_nhn_provider(), + ), + mock.patch( + "prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router.network_client", + new=network_client, + ), + ): + from prowler.providers.nhn.services.network.network_vpc_subnet_has_external_router.network_vpc_subnet_has_external_router import ( + network_vpc_subnet_has_external_router, + ) + + check = network_vpc_subnet_has_external_router() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "no external router" in result[0].status_extended + assert result[0].resource_id == network_id + assert result[0].resource_name == network_name From cb239b20ab5063aebaf7f5897a24b6d65f84b0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 9 Apr 2025 15:34:17 +0200 Subject: [PATCH 139/359] fix(aws): add default session_duration (#7479) --- prowler/providers/aws/aws_provider.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/prowler/providers/aws/aws_provider.py b/prowler/providers/aws/aws_provider.py index 5552af9b43..20b38c20f2 100644 --- a/prowler/providers/aws/aws_provider.py +++ b/prowler/providers/aws/aws_provider.py @@ -105,10 +105,10 @@ class AwsProvider(Provider): self, retries_max_attempts: int = 3, role_arn: str = None, - session_duration: int = None, + session_duration: int = 3600, external_id: str = None, role_session_name: str = None, - mfa: bool = None, + mfa: bool = False, profile: str = None, regions: set = set(), organizations_role_arn: str = None, @@ -238,7 +238,6 @@ class AwsProvider(Provider): profile_region=profile_region, ) ######## - ######## AWS Session with Assume Role (if needed) if role_arn: # Validate the input role From 9f4574f4ff2622e4d1db17260de950e59665ca1d Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 9 Apr 2025 10:34:38 -0400 Subject: [PATCH 140/359] fix: handle errors in AWS and Azure (#7482) --- api/src/backend/config/settings/sentry.py | 5 +++- .../cloudtrail_multi_region_enabled.py | 21 +++++++------- ...ompromised_credentials_sign_in_attempts.py | 1 + ...ks_potential_malicious_sign_in_attempts.py | 28 +++++++++++-------- ...rds_cluster_critical_event_subscription.py | 12 ++++++-- .../aws/services/redshift/redshift_service.py | 2 +- .../azure/services/network/network_service.py | 12 ++++++-- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py index 89c77feba5..5aeda7a88a 100644 --- a/api/src/backend/config/settings/sentry.py +++ b/api/src/backend/config/settings/sentry.py @@ -12,6 +12,8 @@ IGNORED_EXCEPTIONS = [ "UnauthorizedOperation", "AuthFailure", "InvalidClientTokenId", + "AWSInvalidProviderIdError", + "InternalServerErrorException", "AccessDenied", "No Shodan API Key", # Shodan Check "RequestLimitExceeded", # For now we don't want to log the RequestLimitExceeded errors @@ -36,7 +38,7 @@ IGNORED_EXCEPTIONS = [ "InvalidRequestException", "RequestExpired", "ConnectionClosedError", - "HTTPSConnectionPool", + "MaxRetryError", "Pool is closed", # The following comes from urllib3: eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed. # Authentication Errors from GCP "ClientAuthenticationError", @@ -55,6 +57,7 @@ IGNORED_EXCEPTIONS = [ "AzureNotValidClientIdError", "AzureNotValidClientSecretError", "AzureNotValidTenantIdError", + "AzureInvalidProviderIdError", "AzureTenantIdAndClientSecretNotBelongingToClientIdError", "AzureTenantIdAndClientIdNotBelongingToClientSecretError", "AzureClientIdAndClientSecretNotBelongingToTenantIdError", diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py index 0c8ca0439f..b4b7349fc4 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py @@ -9,6 +9,7 @@ class cloudtrail_multi_region_enabled(Check): findings = [] if cloudtrail_client.trails is not None: for region in cloudtrail_client.regional_clients.keys(): + trail_is_logging = False for trail in cloudtrail_client.trails.values(): if trail.region == region or trail.is_multiregion: report = Check_Report_AWS( @@ -16,6 +17,7 @@ class cloudtrail_multi_region_enabled(Check): ) report.region = region if trail.is_logging: + trail_is_logging = True report.status = "PASS" if trail.is_multiregion: report.status_extended = f"Trail {trail.name} is multiregion and it is logging." @@ -25,16 +27,15 @@ class cloudtrail_multi_region_enabled(Check): # Store the finding and exit the loop findings.append(report) break - else: - report.status = "FAIL" - report.status_extended = ( - "No CloudTrail trails enabled with logging were found." - ) - report.resource_arn = ( - cloudtrail_client._get_trail_arn_template(region) - ) - report.resource_id = cloudtrail_client.audited_account # If there are no trails logging it is needed to store the FAIL once all the trails have been checked - if report.status == "FAIL": + if not trail_is_logging: + report.status = "FAIL" + report.status_extended = ( + "No CloudTrail trails enabled with logging were found." + ) + report.resource_arn = cloudtrail_client._get_trail_arn_template( + region + ) + report.resource_id = cloudtrail_client.audited_account findings.append(report) return findings diff --git a/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts.py b/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts.py index 0552c01c57..b0eee2b4b3 100644 --- a/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts.py +++ b/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts/cognito_user_pool_blocks_compromised_credentials_sign_in_attempts.py @@ -9,6 +9,7 @@ class cognito_user_pool_blocks_compromised_credentials_sign_in_attempts(Check): report = Check_Report_AWS(metadata=self.metadata(), resource=pool) if ( pool.advanced_security_mode == "ENFORCED" + and pool.risk_configuration and "SIGN_IN" in pool.risk_configuration.compromised_credentials_risk_configuration.event_filter and pool.risk_configuration.compromised_credentials_risk_configuration.actions diff --git a/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_potential_malicious_sign_in_attempts/cognito_user_pool_blocks_potential_malicious_sign_in_attempts.py b/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_potential_malicious_sign_in_attempts/cognito_user_pool_blocks_potential_malicious_sign_in_attempts.py index 6d0baeded4..6ed3f34d75 100644 --- a/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_potential_malicious_sign_in_attempts/cognito_user_pool_blocks_potential_malicious_sign_in_attempts.py +++ b/prowler/providers/aws/services/cognito/cognito_user_pool_blocks_potential_malicious_sign_in_attempts/cognito_user_pool_blocks_potential_malicious_sign_in_attempts.py @@ -7,18 +7,22 @@ class cognito_user_pool_blocks_potential_malicious_sign_in_attempts(Check): findings = [] for pool in cognito_idp_client.user_pools.values(): report = Check_Report_AWS(metadata=self.metadata(), resource=pool) - if pool.advanced_security_mode == "ENFORCED" and all( - [ - pool.risk_configuration.account_takeover_risk_configuration.low_action - and pool.risk_configuration.account_takeover_risk_configuration.low_action - == "BLOCK", - pool.risk_configuration.account_takeover_risk_configuration.medium_action - and pool.risk_configuration.account_takeover_risk_configuration.medium_action - == "BLOCK", - pool.risk_configuration.account_takeover_risk_configuration.high_action - and pool.risk_configuration.account_takeover_risk_configuration.high_action - == "BLOCK", - ] + if ( + pool.advanced_security_mode == "ENFORCED" + and pool.risk_configuration + and all( + [ + pool.risk_configuration.account_takeover_risk_configuration.low_action + and pool.risk_configuration.account_takeover_risk_configuration.low_action + == "BLOCK", + pool.risk_configuration.account_takeover_risk_configuration.medium_action + and pool.risk_configuration.account_takeover_risk_configuration.medium_action + == "BLOCK", + pool.risk_configuration.account_takeover_risk_configuration.high_action + and pool.risk_configuration.account_takeover_risk_configuration.high_action + == "BLOCK", + ] + ) ): report.status = "PASS" report.status_extended = f"User pool {pool.name} blocks all potential malicious sign-in attempts." diff --git a/prowler/providers/aws/services/rds/rds_cluster_critical_event_subscription/rds_cluster_critical_event_subscription.py b/prowler/providers/aws/services/rds/rds_cluster_critical_event_subscription/rds_cluster_critical_event_subscription.py index 336d2f3d80..4caff14289 100644 --- a/prowler/providers/aws/services/rds/rds_cluster_critical_event_subscription/rds_cluster_critical_event_subscription.py +++ b/prowler/providers/aws/services/rds/rds_cluster_critical_event_subscription/rds_cluster_critical_event_subscription.py @@ -13,23 +13,29 @@ class rds_cluster_critical_event_subscription(Check): report.resource_id = rds_client.audited_account report.resource_arn = rds_client._get_rds_arn_template(db_event.region) if db_event.source_type == "db-cluster" and db_event.enabled: - report = Check_Report_AWS( - metadata=self.metadata(), resource=db_event - ) if db_event.event_list == [] or set(db_event.event_list) == { "maintenance", "failure", }: + report = Check_Report_AWS( + metadata=self.metadata(), resource=db_event + ) report.status = "PASS" report.status_extended = "RDS cluster events are subscribed." elif db_event.event_list == ["maintenance"]: + report = Check_Report_AWS( + metadata=self.metadata(), resource=db_event + ) report.status = "FAIL" report.status_extended = ( "RDS cluster event category of failure is not subscribed." ) elif db_event.event_list == ["failure"]: + report = Check_Report_AWS( + metadata=self.metadata(), resource=db_event + ) report.status = "FAIL" report.status_extended = "RDS cluster event category of maintenance is not subscribed." diff --git a/prowler/providers/aws/services/redshift/redshift_service.py b/prowler/providers/aws/services/redshift/redshift_service.py index 8284b9d05d..b0f4a06421 100644 --- a/prowler/providers/aws/services/redshift/redshift_service.py +++ b/prowler/providers/aws/services/redshift/redshift_service.py @@ -124,7 +124,7 @@ class Redshift(AWSService): try: regional_client = self.regional_clients[cluster.region] cluster_parameter_groups = regional_client.describe_cluster_parameters( - ClusterParameterGroupName=cluster.parameter_group_name + ParameterGroupName=cluster.parameter_group_name ) for parameter_group in cluster_parameter_groups["Parameters"]: if parameter_group["ParameterName"].lower() == "require_ssl": diff --git a/prowler/providers/azure/services/network/network_service.py b/prowler/providers/azure/services/network/network_service.py index c6464133da..fb0e6f90ba 100644 --- a/prowler/providers/azure/services/network/network_service.py +++ b/prowler/providers/azure/services/network/network_service.py @@ -78,8 +78,16 @@ class Network(AzureService): FlowLog( id=flow_log.id, name=flow_log.name, - enabled=flow_log.properties.enabled, - retention_policy=flow_log.properties.retentionPolicy, + enabled=getattr( + getattr(flow_log, "properties", None), + "enabled", + False, + ), + retention_policy=getattr( + getattr(flow_log, "properties", None), + "retentionPolicy", + None, + ), ) for flow_log in flow_logs ], From 73ebf95d894e67b43e1f4aa4a27ca7b795a709c1 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 9 Apr 2025 20:50:56 +0545 Subject: [PATCH 141/359] chore(changelog): Prepare for v5.5.0 (#7484) --- api/CHANGELOG.md | 2 +- ui/CHANGELOG.md | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 9ddd23edc6..fdaff7ea8e 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the **Prowler API** are documented in this file. --- -## [v1.6.0] (Prowler UNRELEASED) +## [v1.6.0] (Prowler v5.5.0) ### Added diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 4293088de4..e01eea9296 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -4,9 +4,9 @@ All notable changes to the **Prowler UI** are documented in this file. --- -### [v1.5.0] (Prowler v5.5.0 - UNRELEASED) +## [v1.5.0] (Prowler v5.5.0) -#### 🚀 Added +### 🚀 Added - Social login integration with Google and GitHub [(#7218)](https://github.com/prowler-cloud/prowler/pull/7218) - Added `one-time scan` feature: Adds support for single scan execution. [(#7188)](https://github.com/prowler-cloud/prowler/pull/7188) @@ -15,7 +15,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Show muted icon when a finding is muted. [(#7378)](https://github.com/prowler-cloud/prowler/pull/7378) - Added static status icon with link to service status page. [(#7468)](https://github.com/prowler-cloud/prowler/pull/7468) -#### 🔄 Changed +### 🔄 Changed - Tweak styles for compliance cards. [(#7148)](https://github.com/prowler-cloud/prowler/pull/7148). - Upgrade Next.js to v14.2.25 to fix a middleware authorization vulnerability. [(#7339)](https://github.com/prowler-cloud/prowler/pull/7339) @@ -24,21 +24,21 @@ All notable changes to the **Prowler UI** are documented in this file. --- -### [v1.4.0] (Prowler v5.4.0) +## [v1.4.0] (Prowler v5.4.0) -#### 🚀 Added +### 🚀 Added - Added `exports` feature: Users can now download artifacts via a new button. [(#7006)](https://github.com/prowler-cloud/prowler/pull/7006) - New sidebar with nested menus and integrated mobile navigation. [(#7018)](https://github.com/prowler-cloud/prowler/pull/7018) - Added animation for scan execution progress—it now updates automatically.[(#6972)](https://github.com/prowler-cloud/prowler/pull/6972) - Add `status_extended` attribute to finding details. [(#6997)](https://github.com/prowler-cloud/prowler/pull/6997) - Add `Prowler version` to the sidebar. [(#7086)](https://github.com/prowler-cloud/prowler/pull/7086) - -#### 🔄 Changed + +### 🔄 Changed - New compliance dropdown. [(#7118)](https://github.com/prowler-cloud/prowler/pull/7118). - -#### 🐞 Fixes + +### 🐞 Fixes - Revalidate the page when a role is deleted. [(#6976)](https://github.com/prowler-cloud/prowler/pull/6976) - Allows removing group visibility when creating a role. [(#7088)](https://github.com/prowler-cloud/prowler/pull/7088) @@ -48,26 +48,26 @@ All notable changes to the **Prowler UI** are documented in this file. --- -### [v1.3.0] (Prowler v5.3.0) +## [v1.3.0] (Prowler v5.3.0) -#### 🚀 Added +### 🚀 Added - Findings endpoints now require at least one date filter [(#6864)](https://github.com/prowler-cloud/prowler/pull/6864). -#### 🔄 Changed +### 🔄 Changed - Scans now appear immediately after launch. [(#6791)](https://github.com/prowler-cloud/prowler/pull/6791). - Improved sign-in and sign-up forms. [(#6813)](https://github.com/prowler-cloud/prowler/pull/6813). --- -### [v1.2.0] (Prowler v5.2.0) +## [v1.2.0] (Prowler v5.2.0) -#### 🚀 Added +### 🚀 Added - `First seen` field included in finding details. [(#6575)](https://github.com/prowler-cloud/prowler/pull/6575) -#### 🔄 Changed +### 🔄 Changed - Completely redesigned finding details layout. [(#6575)](https://github.com/prowler-cloud/prowler/pull/6575) - Completely redesigned scan details layout.[(#6665)](https://github.com/prowler-cloud/prowler/pull/6665) From 5d81869de4213c49e8bfada061618d01d60d5ec5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 22:31:33 -0400 Subject: [PATCH 142/359] chore(deps): bump tj-actions/changed-files from 46.0.4 to 46.0.5 (#7486) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-pull-request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 6f79e385b2..0c8cbf5d7d 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -75,7 +75,7 @@ jobs: - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@6cb76d07bee4c9772c6882c06c37837bf82a04d3 # v46.0.4 + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: api/** files_ignore: | diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 9e224f8051..37838feefa 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -25,7 +25,7 @@ jobs: - name: Test if changes are in not ignored paths id: are-non-ignored-files-changed - uses: tj-actions/changed-files@6cb76d07bee4c9772c6882c06c37837bf82a04d3 # v46.0.4 + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: ./** files_ignore: | From d3a5a5c0a1ad15f124b2e995c1d38672a547904b Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 11 Apr 2025 09:59:10 +0200 Subject: [PATCH 143/359] fix: resolve social login issue in AuthForm on sign-up page (#7490) --- ui/app/(auth)/sign-up/page.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/app/(auth)/sign-up/page.tsx b/ui/app/(auth)/sign-up/page.tsx index 37f1bc92f7..6dc5c81c87 100644 --- a/ui/app/(auth)/sign-up/page.tsx +++ b/ui/app/(auth)/sign-up/page.tsx @@ -1,5 +1,5 @@ import { AuthForm } from "@/components/auth/oss"; -import { isGithubOAuthEnabled } from "@/lib/helper"; +import { getAuthUrl, isGithubOAuthEnabled } from "@/lib/helper"; import { isGoogleOAuthEnabled } from "@/lib/helper"; import { SearchParamsProps } from "@/types"; @@ -9,10 +9,15 @@ const SignUp = ({ searchParams }: { searchParams: SearchParamsProps }) => { ? searchParams.invitation_token : null; + const GOOGLE_AUTH_URL = getAuthUrl("google"); + const GITHUB_AUTH_URL = getAuthUrl("github"); + return ( From a5c6fee5b4182ee6632599f1c71f0023a1190b86 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 11 Apr 2025 14:40:28 +0200 Subject: [PATCH 144/359] fix: update redirect URL for SSO (#7493) --- ui/app/api/auth/callback/github/route.ts | 2 +- ui/app/api/auth/callback/google/route.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/api/auth/callback/github/route.ts b/ui/app/api/auth/callback/github/route.ts index 2c70a8cd88..d913844644 100644 --- a/ui/app/api/auth/callback/github/route.ts +++ b/ui/app/api/auth/callback/github/route.ts @@ -53,7 +53,7 @@ export async function GET(req: Request) { // eslint-disable-next-line no-console console.error("SignIn error:", error); return NextResponse.redirect( - new URL("/sign-in?error=AuthenticationFailed", req.url), + new URL("/sign-in?error=AuthenticationFailed", baseUrl), ); } } catch (error) { diff --git a/ui/app/api/auth/callback/google/route.ts b/ui/app/api/auth/callback/google/route.ts index 0f92d8ef46..37fea85f00 100644 --- a/ui/app/api/auth/callback/google/route.ts +++ b/ui/app/api/auth/callback/google/route.ts @@ -53,7 +53,7 @@ export async function GET(req: Request) { // eslint-disable-next-line no-console console.error("SignIn error:", error); return NextResponse.redirect( - new URL("/sign-in?error=AuthenticationFailed", req.url), + new URL("/sign-in?error=AuthenticationFailed", baseUrl), ); } } catch (error) { From 22141f9706e1ffb48d9d525a53db937529fd89b6 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 14 Apr 2025 17:46:13 +0545 Subject: [PATCH 145/359] fix(findings): increase uid max length to 600 (#7498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Víctor Fernández Poyatos --- api/CHANGELOG.md | 5 ++++ api/pyproject.toml | 2 +- .../api/migrations/0017_alter_finding_uid.py | 17 +++++++++++ api/src/backend/api/models.py | 2 +- api/src/backend/api/specs/v1.yaml | 4 +-- api/src/backend/api/tests/test_models.py | 30 ++++++++++++++++++- api/src/backend/api/v1/views.py | 2 +- 7 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 api/src/backend/api/migrations/0017_alter_finding_uid.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index fdaff7ea8e..46ab5ecaa6 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to the **Prowler API** are documented in this file. +## [v1.6.1] (Prowler UNRELEASED) + +### Changed +- Changed `findings.uid` field length from `varchar(300)` to `varchar(600)` [(#7498)](https://github.com/prowler-cloud/prowler/pull/7498). + --- ## [v1.6.0] (Prowler v5.5.0) diff --git a/api/pyproject.toml b/api/pyproject.toml index d8e74d6260..9b9edfbac6 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -35,7 +35,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.6.0" +version = "1.6.1" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/api/migrations/0017_alter_finding_uid.py b/api/src/backend/api/migrations/0017_alter_finding_uid.py new file mode 100644 index 0000000000..4c72d1b9a2 --- /dev/null +++ b/api/src/backend/api/migrations/0017_alter_finding_uid.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.7 on 2025-04-14 06:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0016_finding_compliance_resource_details_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="finding", + name="uid", + field=models.CharField(max_length=600), + ), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 69b7ead46a..bede403194 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -641,7 +641,7 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel): updated_at = models.DateTimeField(auto_now=True, editable=False) first_seen_at = models.DateTimeField(editable=False, null=True) - uid = models.CharField(max_length=300) + uid = models.CharField(max_length=600) delta = FindingDeltaEnumField( choices=DeltaChoices.choices, blank=True, diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 30c9dbb675..39464648fe 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.6.0 + version: 1.6.1 description: |- Prowler API specification. @@ -6228,7 +6228,7 @@ components: properties: uid: type: string - maxLength: 300 + maxLength: 600 delta: enum: - new diff --git a/api/src/backend/api/tests/test_models.py b/api/src/backend/api/tests/test_models.py index b6ef1a66c9..25ee7d9ad9 100644 --- a/api/src/backend/api/tests/test_models.py +++ b/api/src/backend/api/tests/test_models.py @@ -1,6 +1,6 @@ import pytest -from api.models import Resource, ResourceTag +from api.models import Finding, Resource, ResourceTag, StatusChoices @pytest.mark.django_db @@ -92,3 +92,31 @@ class TestResourceModel: assert len(resource.tags.filter(tenant_id=tenant_id)) == 0 assert resource.get_tags(tenant_id=tenant_id) == {} + + +@pytest.mark.django_db +class TestFindingModel: + def test_add_finding_with_long_uid( + self, providers_fixture, scans_fixture, resources_fixture + ): + provider, *_ = providers_fixture + tenant_id = provider.tenant_id + + long_uid = "1" * 500 + _ = Finding.objects.create( + tenant_id=tenant_id, + uid=long_uid, + delta=Finding.DeltaChoices.NEW, + check_metadata={}, + status=StatusChoices.PASS, + status_extended="", + severity="high", + impact="high", + raw_result={}, + check_id="test_check", + scan=scans_fixture[0], + first_seen_at=None, + muted=False, + compliance={}, + ) + assert Finding.objects.filter(uid=long_uid).exists() diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index e8dd81ac29..40e4c59071 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -247,7 +247,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.6.0" + spectacular_settings.VERSION = "1.6.1" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." ) From 14ef169e997cbb5cd0115f9b480d0092ca536f2c Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 14 Apr 2025 15:22:21 +0200 Subject: [PATCH 146/359] chore(regions_update): Changes in regions for AWS services (#7497) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 4a3b4bac59..7cd793fd7a 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -6005,6 +6005,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -6018,6 +6019,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -8392,6 +8394,7 @@ "qdeveloper": { "regions": { "aws": [ + "eu-central-1", "us-east-1" ], "aws-cn": [], @@ -8853,6 +8856,8 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -8866,6 +8871,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From d6ec4c2c9620aee536906194555bc7c6b618676a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 14 Apr 2025 15:22:50 +0200 Subject: [PATCH 147/359] feat(sdk): add changelog file (#7499) --- .github/pull_request_template.md | 1 + prowler/CHANGELOG.md | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 prowler/CHANGELOG.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9a417cc5d0..f98e90fd03 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,6 +16,7 @@ Please include a summary of the change and which issue is fixed. List any depend - [ ] Review if code is being documented following this specification https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings - [ ] Review if backport is needed. - [ ] Review if is needed to change the [Readme.md](https://github.com/prowler-cloud/prowler/blob/master/README.md) +- [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/prowler/CHANGELOG.md), if applicable. #### API - [ ] Verify if API specs need to be regenerated. diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md new file mode 100644 index 0000000000..3b3c514634 --- /dev/null +++ b/prowler/CHANGELOG.md @@ -0,0 +1,13 @@ +# Prowler SDK Changelog + +All notable changes to the **Prowler SDK** are documented in this file. + +--- + +## [v5.5.0] + +### Added + +### Fixed + +--- From 9b773897d2002a091054d917980f8ae09cbe8494 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 14 Apr 2025 15:53:40 +0200 Subject: [PATCH 148/359] chore(regions_update): Changes in regions for AWS services (#7487) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> From afe0b7443f7facc389f6bf2c8dde1b3fab08095c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 14 Apr 2025 16:16:07 +0200 Subject: [PATCH 149/359] fix(defender): add default name to contacts (#7483) --- prowler/lib/outputs/finding.py | 2 +- prowler/providers/azure/services/defender/defender_service.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index a1e68047fa..b1c8299887 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -284,7 +284,7 @@ class Finding(BaseModel): if not output_data["resource_uid"]: logger.error( - f"Check {check_output.check_metadata.CheckID} has no resource_id." + f"Check {check_output.check_metadata.CheckID} has no resource_uid." ) if not output_data["resource_name"]: logger.error( diff --git a/prowler/providers/azure/services/defender/defender_service.py b/prowler/providers/azure/services/defender/defender_service.py index d400043653..f308a838bd 100644 --- a/prowler/providers/azure/services/defender/defender_service.py +++ b/prowler/providers/azure/services/defender/defender_service.py @@ -161,7 +161,7 @@ class Defender(AzureService): { security_contact_default.name: SecurityContacts( resource_id=security_contact_default.id, - name=security_contact_default.name, + name=security_contact_default.get("name", "default"), emails=security_contact_default.emails, phone=security_contact_default.phone, alert_notifications_minimal_severity=security_contact_default.alert_notifications.minimal_severity, From ceda8c76d2bca81fa455a3d35e1c8d9fa3882086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 14 Apr 2025 16:16:20 +0200 Subject: [PATCH 150/359] feat(azure): add SOC2 compliance framework (#7489) --- README.md | 2 +- dashboard/compliance/soc2_azure.py | 24 + prowler/compliance/azure/soc2_azure.json | 623 +++++++++++++++++++++++ 3 files changed, 648 insertions(+), 1 deletion(-) create mode 100644 dashboard/compliance/soc2_azure.py create mode 100644 prowler/compliance/azure/soc2_azure.json diff --git a/README.md b/README.md index f7592cdf98..9922038378 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe |---|---|---|---|---| | AWS | 564 | 82 | 33 | 10 | | GCP | 78 | 13 | 7 | 3 | -| Azure | 140 | 18 | 7 | 3 | +| Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | | Microsoft365 | 5 | 2 | 1 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | diff --git a/dashboard/compliance/soc2_azure.py b/dashboard/compliance/soc2_azure.py new file mode 100644 index 0000000000..2d5517aed6 --- /dev/null +++ b/dashboard/compliance/soc2_azure.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_format3 + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_format3( + aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID" + ) diff --git a/prowler/compliance/azure/soc2_azure.json b/prowler/compliance/azure/soc2_azure.json new file mode 100644 index 0000000000..ccbf57acfe --- /dev/null +++ b/prowler/compliance/azure/soc2_azure.json @@ -0,0 +1,623 @@ +{ + "Framework": "SOC2", + "Version": "", + "Provider": "Azure", + "Description": "System and Organization Controls (SOC), defined by the American Institute of Certified Public Accountants (AICPA), is the name of a set of reports that's produced during an audit. It's intended for use by service organizations (organizations that provide information systems as a service to other organizations) to issue validated reports of internal controls over those information systems to the users of those services. The reports focus on controls grouped into five categories known as Trust Service Principles.", + "Requirements": [ + { + "Id": "cc_1_3", + "Name": "CC1.3 COSO Principle 3: Management establishes, with board oversight, structures, reporting lines, and appropriate authorities and responsibilities in the pursuit of objectives", + "Description": "Considers All Structures of the Entity - Management and the board of directors consider the multiple structures used (including operating units, legal entities, geographic distribution, and outsourced service providers) to support the achievement of objectives. Establishes Reporting Lines - Management designs and evaluates lines of reporting for each entity structure to enable execution of authorities and responsibilities and flow of information to manage the activities of the entity. Defines, Assigns, and Limits Authorities and Responsibilities - Management and the board of directors delegate authority, define responsibilities, and use appropriate processes and technology to assign responsibility and segregate duties as necessary at the various levels of the organization. Additional points of focus specifically related to all engagements using the trust services criteria: Addresses Specific Requirements When Defining Authorities and Responsibilities—Management and the board of directors consider requirements relevant to security, availability, processing integrity, confidentiality, and privacy when defining authorities and responsibilities. Considers Interactions With External Parties When Establishing Structures, Reporting Lines, Authorities, and Responsibilities — Management and the board of directors consider the need for the entity to interact with and monitor the activities of external parties when establishing structures, reporting lines, authorities, and responsibilities.", + "Attributes": [ + { + "ItemId": "cc_1_3", + "Section": "CC1.0 - Common Criteria Related to Control Environment", + "Service": "entra", + "Type": "automated" + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api", + "entra_global_admin_in_less_than_five_users", + "entra_non_privileged_user_has_mfa", + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps", + "entra_policy_ensure_default_user_cannot_create_tenants", + "entra_policy_guest_invite_only_for_admin_roles", + "entra_policy_guest_users_access_restrictions", + "entra_policy_restricts_user_consent_for_apps", + "entra_policy_user_consent_for_verified_apps", + "entra_privileged_user_has_mfa", + "entra_security_defaults_enabled", + "entra_trusted_named_locations_exists", + "entra_user_with_vm_access_has_mfa", + "entra_users_cannot_create_microsoft_365_groups" + ] + }, + { + "Id": "cc_2_1", + "Name": "CC2.1 COSO Principle 13: The entity obtains or generates and uses relevant, quality information to support the functioning of internal control", + "Description": "Identifies Information Requirements - A process is in place to identify the information required and expected to support the functioning of the other components of internal control and the achievement of the entity’s objectives. Captures Internal and External Sources of Data - Information systems capture internal and external sources of data. Processes Relevant Data Into Information - Information systems process and transform relevant data into information. Maintains Quality Throughout Processing - Information systems produce information that is timely, current, accurate, complete, accessible, protected, verifiable, and retained. Information is reviewed to assess its relevance in supporting the internal control components.", + "Attributes": [ + { + "ItemId": "cc_2_1", + "Section": "CC2.0 - Common Criteria Related to Communication and Information", + "Service": "monitor", + "Type": "automated" + } + ], + "Checks": [ + "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_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr" + ] + }, + { + "Id": "cc_3_1", + "Name": "CC3.1 COSO Principle 6: The entity specifies objectives with sufficient clarity to enable the identification and assessment of risks relating to objectives", + "Description": "Operations Objectives: Reflects Management's Choices - Operations objectives reflect management's choices about structure, industry considerations, and performance of the entity. Considers Tolerances for Risk - Management considers the acceptable levels of variation relative to the achievement of operations objectives. External Financial Reporting Objectives: Complies With Applicable Accounting Standards - Financial reporting objectives are consistent with accounting principles suitable and available for that entity. The accounting principles selected are appropriate in the circumstances. External Nonfinancial Reporting Objectives: Complies With Externally Established Frameworks - Management establishes objectives consistent with laws and regulations or standards and frameworks of recognized external organizations. Reflects Entity Activities - External reporting reflects the underlying transactions and events within a range of acceptable limits. Considers the Required Level of Precision—Management reflects the required level of precision and accuracy suitable for user needs and based on criteria established by third parties in nonfinancial reporting. Internal Reporting Objectives: Reflects Management's Choices - Internal reporting provides management with accurate and complete information regarding management's choices and information needed in managing the entity. Considers the Required Level of Precision—Management reflects the required level of precision and accuracy suitable for user needs in nonfinancial reporting objectives and materiality within financial reporting objectives. Reflects Entity Activities—Internal reporting reflects the underlying transactions and events within a range of acceptable limits. Compliance Objectives: Reflects External Laws and Regulations - Laws and regulations establish minimum standards of conduct, which the entity integrates into compliance objectives. Considers Tolerances for Risk - Management considers the acceptable levels of variation relative to the achievement of operations objectives. Additional point of focus specifically related to all engagements using the trust services criteria: Establishes Sub-objectives to Support Objectives—Management identifies sub-objectives related to security, availability, processing integrity, confidentiality, and privacy to support the achievement of the entity’s objectives related to reporting, operations, and compliance.", + "Attributes": [ + { + "ItemId": "cc_3_1", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_system_updates_are_applied", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled" + ] + }, + { + "Id": "cc_3_2", + "Name": "CC3.2 COSO Principle 7: The entity identifies risks to the achievement of its objectives across the entity and analyzes risks as a basis for determining how the risks should be managed", + "Description": "Includes Entity, Subsidiary, Division, Operating Unit, and Functional Levels - The entity identifies and assesses risk at the entity, subsidiary, division, operating unit, and functional levels relevant to the achievement of objectives. Analyzes Internal and External Factors - Risk identification considers both internal and external factors and their impact on the achievement of objectives. Involves Appropriate Levels of Management - The entity puts into place effective risk assessment mechanisms that involve appropriate levels of management. Estimates Significance of Risks Identified - Identified risks are analyzed through a process that includes estimating the potential significance of the risk. Determines How to Respond to Risks - Risk assessment includes considering how the risk should be managed and whether to accept, avoid, reduce, or share the risk. Additional points of focus specifically related to all engagements using the trust services criteria: Identifies and Assesses Criticality of Information Assets and Identifies Threats and Vulnerabilities - The entity's risk identification and assessment process includes (1) identifying information assets, including physical devices and systems, virtual devices, software, data and data flows, external information systems, and organizational roles; (2) assessing the criticality of those information assets; (3) identifying the threats to the assets from intentional (including malicious) and unintentional acts and environmental events; and (4) identifying the vulnerabilities of the identified assets.", + "Attributes": [ + { + "ItemId": "cc_3_2", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_assessments_vm_endpoint_protection_installed", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_system_updates_are_applied", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled" + ] + }, + { + "Id": "cc_3_3", + "Name": "CC3.3 COSO Principle 8: The entity considers the potential for fraud in assessing risks to the achievement of objectives", + "Description": "Considers Various Types of Fraud - The assessment of fraud considers fraudulent reporting, possible loss of assets, and corruption resulting from the various ways that fraud and misconduct can occur. Assesses Incentives and Pressures - The assessment of fraud risks considers incentives and pressures. Assesses Opportunities - The assessment of fraud risk considers opportunities for unauthorized acquisition,use, or disposal of assets, altering the entity’s reporting records, or committing other inappropriate acts. Assesses Attitudes and Rationalizations - The assessment of fraud risk considers how management and other personnel might engage in or justify inappropriate actions. Additional point of focus specifically related to all engagements using the trust services criteria: Considers the Risks Related to the Use of IT and Access to Information - The assessment of fraud risks includes consideration of threats and vulnerabilities that arise specifically from the use of IT and access to information.", + "Attributes": [ + { + "ItemId": "cc_3_3", + "Section": "CC3.0 - Common Criteria Related to Risk Assessment", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "aks_clusters_created_with_private_nodes", + "app_function_identity_without_admin_privileges", + "containerregistry_uses_private_link", + "cosmosdb_account_use_private_endpoints", + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa", + "keyvault_private_endpoints", + "monitor_storage_account_with_activity_logs_is_private", + "storage_ensure_private_endpoints_in_storage_accounts" + ] + }, + { + "Id": "cc_4_2", + "Name": "CC4.2 COSO Principle 17: The entity evaluates and communicates internal control deficiencies in a timely manner to those parties responsible for taking corrective action, including senior management and the board of directors, as appropriate", + "Description": "Assesses Results - Management and the board of directors, as appropriate, assess results of ongoing and separate evaluations. Communicates Deficiencies - Deficiencies are communicated to parties responsible for taking corrective action and to senior management and the board of directors, as appropriate. Monitors Corrective Action - Management tracks whether deficiencies are remedied on a timely basis.", + "Attributes": [ + { + "ItemId": "cc_4_2", + "Section": "CC4.0 - Monitoring Activities", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_assessments_vm_endpoint_protection_installed", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_system_updates_are_applied", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled" + ] + }, + { + "Id": "cc_5_2", + "Name": "CC5.2 COSO Principle 11: The entity also selects and develops general control activities over technology to support the achievement of objectives", + "Description": "Determines Dependency Between the Use of Technology in Business Processes and Technology General Controls - Management understands and determines the dependency and linkage between business processes, automated control activities, and technology general controls. Establishes Relevant Technology Infrastructure Control Activities - Management selects and develops control activities over the technology infrastructure, which are designed and implemented to help ensure the completeness, accuracy, and availability of technology processing. Establishes Relevant Security Management Process Controls Activities - Management selects and develops control activities that are designed and implemented to restrict technology access rights to authorized users commensurate with their job responsibilities and to protect the entity’s assets from external threats. Establishes Relevant Technology Acquisition, Development, and Maintenance Process Control Activities - Management selects and develops control activities over the acquisition, development, and maintenance of technology and its infrastructure to achieve management’s objectives.", + "Attributes": [ + { + "ItemId": "cc_5_2", + "Section": "CC5.0 - Control Activities", + "Service": "monitor", + "Type": "automated" + } + ], + "Checks": [ + "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_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr" + ] + }, + { + "Id": "cc_6_1", + "Name": "CC6.1 The entity implements logical access security software, infrastructure, and architectures over protected information assets to protect them from security events to meet the entity's objectives", + "Description": "Identifies and Manages the Inventory of Information Assets - The entity identifies, inventories, classifies, and manages information assets. Restricts Logical Access - Logical access to information assets, including hardware, data (at-rest, during processing, or in transmission), software, administrative authorities, mobile devices, output, and offline system components is restricted through the use of access control software and rule sets. Identifies and Authenticates Users - Persons, infrastructure and software are identified and authenticated prior to accessing information assets, whether locally or remotely. Considers Network Segmentation - Network segmentation permits unrelated portions of the entity's information system to be isolated from each other. Manages Points of Access - Points of access by outside entities and the types of data that flow through the points of access are identified, inventoried, and managed. The types of individuals and systems using each point of access are identified, documented, and managed. Restricts Access to Information Assets - Combinations of data classification, separate data structures, port restrictions, access protocol restrictions, user identification, and digital certificates are used to establish access control rules for information assets. Manages Identification and Authentication - Identification and authentication requirements are established, documented, and managed for individuals and systems accessing entity information, infrastructure and software. Manages Credentials for Infrastructure and Software - New internal and external infrastructure and software are registered, authorized, and documented prior to being granted access credentials and implemented on the network or access point. Credentials are removed and access is disabled when access is no longer required or the infrastructure and software are no longer in use. Uses Encryption to Protect Data - The entity uses encryption to supplement other measures used to protect data-at-rest, when such protections are deemed appropriate based on assessed risk. Protects Encryption Keys - Processes are in place to protect encryption keys during generation, storage, use, and destruction.", + "Attributes": [ + { + "ItemId": "cc_6_1", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "aks_clusters_public_access_disabled", + "app_function_not_publicly_accessible", + "containerregistry_not_publicly_accessible", + "network_public_ip_shodan", + "storage_blob_public_access_level_is_disabled" + ] + }, + { + "Id": "cc_6_2", + "Name": "CC6.2 Prior to issuing system credentials and granting system access, the entity registers and authorizes new internal and external users whose access is administered by the entity", + "Description": "Prior to issuing system credentials and granting system access, the entity registers and authorizes new internal and external users whose access is administered by the entity. For those users whose access is administered by the entity, user system credentials are removed when user access is no longer authorized. Controls Access Credentials to Protected Assets - Information asset access credentials are created based on an authorization from the system's asset owner or authorized custodian. Removes Access to Protected Assets When Appropriate - Processes are in place to remove credential access when an individual no longer requires such access. Reviews Appropriateness of Access Credentials - The appropriateness of access credentials is reviewed on a periodic basis for unnecessary and inappropriate individuals with credentials.", + "Attributes": [ + { + "ItemId": "cc_6_2", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "mysql_flexible_server_minimum_tls_version_12", + "mysql_flexible_server_ssl_connection_enabled", + "postgresql_flexible_server_enforce_ssl_enabled", + "sqlserver_recommended_minimal_tls_version", + "sqlserver_tde_encrypted_with_cmk", + "sqlserver_tde_encryption_enabled", + "sqlserver_unrestricted_inbound_access", + "storage_secure_transfer_required_is_enabled" + ] + }, + { + "Id": "cc_6_3", + "Name": "CC6.3 The entity authorizes, modifies, or removes access to data, software, functions, and other protected information assets based on roles, responsibilities, or the system design and changes, giving consideration to the concepts of least privilege and segregation of duties, to meet the entity’s objectives", + "Description": "Creates or Modifies Access to Protected Information Assets - Processes are in place to create or modify access to protected information assets based on authorization from the asset’s owner. Removes Access to Protected Information Assets - Processes are in place to remove access to protected information assets when an individual no longer requires access. Uses Role-Based Access Controls - Role-based access control is utilized to support segregation of incompatible functions.", + "Attributes": [ + { + "ItemId": "cc_6_3", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "entra", + "Type": "automated" + } + ], + "Checks": [ + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa" + ] + }, + { + "Id": "cc_6_6", + "Name": "CC6.6 The entity implements logical access security measures to protect against threats from sources outside its system boundaries", + "Description": "Restricts Access — The types of activities that can occur through a communication channel (for example, FTP site, router port) are restricted. Protects Identification and Authentication Credentials — Identification and authentication credentials are protected during transmission outside its system boundaries. Requires Additional Authentication or Credentials — Additional authentication information or credentials are required when accessing the system from outside its boundaries. Implements Boundary Protection Systems — Boundary protection systems (for example, firewalls, demilitarized zones, and intrusion detection systems) are implemented to protect external access points from attempts and unauthorized access and are monitored to detect such attempts.", + "Attributes": [ + { + "ItemId": "cc_6_6", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "network_http_internet_access_restricted", + "network_rdp_internet_access_restricted", + "network_ssh_internet_access_restricted", + "network_udp_internet_access_restricted", + "mysql_flexible_server_ssl_connection_enabled", + "postgresql_flexible_server_enforce_ssl_enabled", + "app_minimum_tls_version_12", + "mysql_flexible_server_minimum_tls_version_12", + "sqlserver_recommended_minimal_tls_version", + "storage_ensure_minimum_tls_version_12" + ] + }, + { + "Id": "cc_6_7", + "Name": "CC6.7 The entity restricts the transmission, movement, and removal of information to authorized internal and external users and processes, and protects it during transmission, movement, or removal to meet the entity’s objectives", + "Description": "Restricts the Ability to Perform Transmission - Data loss prevention processes and technologies are used to restrict ability to authorize and execute transmission, movement and removal of information. Uses Encryption Technologies or Secure Communication Channels to Protect Data - Encryption technologies or secured communication channels are used to protect transmission of data and other communications beyond connectivity access points. Protects Removal Media - Encryption technologies and physical asset protections are used for removable media (such as USB drives and back-up tapes), as appropriate. Protects Mobile Devices - Processes are in place to protect mobile devices (such as laptops, smart phones and tablets) that serve as information assets.", + "Attributes": [ + { + "ItemId": "cc_6_7", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "app_minimum_tls_version_12", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "sqlserver_tde_encrypted_with_cmk", + "sqlserver_tde_encryption_enabled", + "storage_ensure_encryption_with_customer_managed_keys", + "storage_infrastructure_encryption_is_enabled", + "storage_secure_transfer_required_is_enabled", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "cc_6_8", + "Name": "CC6.8 The entity implements controls to prevent or detect and act upon the introduction of unauthorized or malicious software to meet the entity’s objectives", + "Description": "Restricts Application and Software Installation - The ability to install applications and software is restricted to authorized individuals. Detects Unauthorized Changes to Software and Configuration Parameters - Processes are in place to detect changes to software and configuration parameters that may be indicative of unauthorized or malicious software. Uses a Defined Change Control Process - A management-defined change control process is used for the implementation of software. Uses Antivirus and Anti-Malware Software - Antivirus and anti-malware software is implemented and maintained to provide for the interception or detection and remediation of malware. Scans Information Assets from Outside the Entity for Malware and Other Unauthorized Software - Procedures are in place to scan information assets that have been transferred or returned to the entity’s custody for malware and other unauthorized software and to remove any items detected prior to its implementation on the network.", + "Attributes": [ + { + "ItemId": "cc_6_8", + "Section": "CC6.0 - Logical and Physical Access", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_assessments_vm_endpoint_protection_installed", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_system_updates_are_applied", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled" + ] + }, + { + "Id": "cc_7_1", + "Name": "CC7.1 To meet its objectives, the entity uses detection and monitoring procedures to identify (1) changes to configurations that result in the introduction of new vulnerabilities, and (2) susceptibilities to newly discovered vulnerabilities", + "Description": "Uses Defined Configuration Standards - Management has defined configuration standards. Monitors Infrastructure and Software - The entity monitors infrastructure and software for noncompliance with the standards, which could threaten the achievement of the entity's objectives. Implements Change-Detection Mechanisms - The IT system includes a change-detection mechanism (for example, file integrity monitoring tools) to alert personnel to unauthorized modifications of critical system files, configuration files, or content files. Detects Unknown or Unauthorized Components - Procedures are in place to detect the introduction of unknown or unauthorized components. Conducts Vulnerability Scans - The entity conducts vulnerability scans designed to identify potential vulnerabilities or misconfigurations on a periodic basis and after any significant change in the environment and takes action to remediate identified deficiencies on a timely basis.", + "Attributes": [ + { + "ItemId": "cc_7_1", + "Section": "CC7.0 - System Operations", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_assessments_vm_endpoint_protection_installed", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_system_updates_are_applied", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled" + ] + }, + { + "Id": "cc_7_2", + "Name": "CC7.2 The entity monitors system components and the operation of those components for anomalies that are indicative of malicious acts, natural disasters, and errors affecting the entity's ability to meet its objectives; anomalies are analyzed to determine whether they represent security events", + "Description": "Implements Detection Policies, Procedures, and Tools - Detection policies and procedures are defined and implemented, and detection tools are implemented on Infrastructure and software to identify anomalies in the operation or unusual activity on systems. Procedures may include (1) a defined governance process for security event detection and management that includes provision of resources; (2) use of intelligence sources to identify newly discovered threats and vulnerabilities; and (3) logging of unusual system activities. Designs Detection Measures - Detection measures are designed to identify anomalies that could result from actual or attempted (1) compromise of physical barriers; (2) unauthorized actions of authorized personnel; (3) use of compromised identification and authentication credentials; (4) unauthorized access from outside the system boundaries; (5) compromise of authorized external parties; and (6) implementation or connection of unauthorized hardware and software. Implements Filters to Analyze Anomalies - Management has implemented procedures to filter, summarize, and analyze anomalies to identify security events. Monitors Detection Tools for Effective Operation - Management has implemented processes to monitor the effectiveness of detection tools.", + "Attributes": [ + { + "ItemId": "cc_7_2", + "Section": "CC7.0 - System Operations", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "app_http_logs_enabled", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "keyvault_logging_enabled", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "mysql_flexible_server_audit_log_connection_activated", + "mysql_flexible_server_audit_log_enabled", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "postgresql_flexible_server_log_checkpoints_on", + "postgresql_flexible_server_log_connections_on", + "postgresql_flexible_server_log_disconnections_on", + "postgresql_flexible_server_log_retention_days_greater_3" + ] + }, + { + "Id": "cc_7_3", + "Name": "CC7.3 The entity evaluates security events to determine whether they could or have resulted in a failure of the entity to meet its objectives (security incidents) and, if so, takes actions to prevent or address such failures", + "Description": "Responds to Security Incidents - Procedures are in place for responding to security incidents and evaluating the effectiveness of those policies and procedures on a periodic basis. Communicates and Reviews Detected Security Events - Detected security events are communicated to and reviewed by the individuals responsible for the management of the security program and actions are taken, if necessary. Develops and Implements Procedures to Analyze Security Incidents - Procedures are in place to analyze security incidents and determine system impact. Assesses the Impact on Personal Information - Detected security events are evaluated to determine whether they could or did result in the unauthorized disclosure or use of personal information and whether there has been a failure to comply with applicable laws or regulations. Determines Personal Information Used or Disclosed - When an unauthorized use or disclosure of personal information has occurred, the affected information is identified.", + "Attributes": [ + { + "ItemId": "cc_7_3", + "Section": "CC7.0 - System Operations", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "app_http_logs_enabled", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "keyvault_logging_enabled", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "mysql_flexible_server_audit_log_connection_activated", + "mysql_flexible_server_audit_log_enabled", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "postgresql_flexible_server_log_checkpoints_on", + "postgresql_flexible_server_log_connections_on", + "postgresql_flexible_server_log_disconnections_on", + "postgresql_flexible_server_log_retention_days_greater_3", + "defender_ensure_notify_alerts_severity_is_high", + "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_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr" + ] + }, + { + "Id": "cc_7_4", + "Name": "CC7.4 The entity responds to identified security incidents by executing a defined incident response program to understand, contain, remediate, and communicate security incidents, as appropriate", + "Description": "Assigns Roles and Responsibilities - Roles and responsibilities for the design, implementation, maintenance, and execution of the incident response program are assigned, including the use of external resources when necessary. Contains Security Incidents - Procedures are in place to contain security incidents that actively threaten entity objectives. Mitigates Ongoing Security Incidents - Procedures are in place to mitigate the effects of ongoing security incidents. Ends Threats Posed by Security Incidents - Procedures are in place to end the threats posed by security incidents through closure of the vulnerability, removal of unauthorized access, and other remediation actions. Restores Operations - Procedures are in place to restore data and business operations to an interim state that permits the achievement of entity objectives. Develops and Implements Communication Protocols for Security Incidents - Protocols for communicating security incidents and actions taken to affected parties are developed and implemented to meet the entity's objectives. Obtains Understanding of Nature of Incident and Determines Containment Strategy - An understanding of the nature (for example, the method by which the incident occurred and the affected system resources) and severity of the security incident is obtained to determine the appropriate containment strategy, including (1) a determination of the appropriate response time frame, and (2) the determination and execution of the containment approach. Remediates Identified Vulnerabilities - Identified vulnerabilities are remediated through the development and execution of remediation activities. Communicates Remediation Activities - Remediation activities are documented and communicated in accordance with the incident response program. Evaluates the Effectiveness of Incident Response - The design of incident response activities is evaluated for effectiveness on a periodic basis. Periodically Evaluates Incidents - Periodically, management reviews incidents related to security, availability, processing integrity, confidentiality, and privacy and identifies the need for system changes based on incident patterns and root causes. Communicates Unauthorized Use and Disclosure - Events that resulted in unauthorized use or disclosure of personal information are communicated to the data subjects, legal and regulatory authorities, and others as required. Application of Sanctions - The conduct of individuals and organizations operating under the authority of the entity and involved in the unauthorized use or disclosure of personal information is evaluated and, if appropriate, sanctioned in accordance with entity policies and legal and regulatory requirements.", + "Attributes": [ + { + "ItemId": "cc_7_4", + "Section": "CC7.0 - System Operations", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "defender_ensure_notify_alerts_severity_is_high", + "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_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr", + "storage_ensure_soft_delete_is_enabled", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "cc_7_5", + "Name": "CC7.5 The entity identifies, develops, and implements activities to recover from identified security incidents", + "Description": "Restores the Affected Environment - The activities restore the affected environment to functional operation by rebuilding systems, updating software, installing patches, and changing configurations, as needed. Communicates Information About the Event - Communications about the nature of the incident, recovery actions taken, and activities required for the prevention of future security events are made to management and others as appropriate (internal and external). Determines Root Cause of the Event - The root cause of the event is determined. Implements Changes to Prevent and Detect Recurrences - Additional architecture or changes to preventive and detective controls, or both, are implemented to prevent and detect recurrences on a timely basis. Improves Response and Recovery Procedures - Lessons learned are analyzed, and the incident response plan and recovery procedures are improved. Implements Incident Recovery Plan Testing - Incident recovery plan testing is performed on a periodic basis. The testing includes (1) development of testing scenarios based on threat likelihood and magnitude; (2) consideration of relevant system components from across the entity that can impair availability; (3) scenarios that consider the potential for the lack of availability of key personnel; and (4) revision of continuity plans and systems based on test results.", + "Attributes": [ + { + "ItemId": "cc_7_5", + "Section": "CC7.0 - System Operations", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk", + "storage_ensure_encryption_with_customer_managed_keys", + "storage_infrastructure_encryption_is_enabled" + ] + }, + { + "Id": "cc_8_1", + "Name": "CC8.1 The entity authorizes, designs, develops or acquires, configures, documents, tests, approves, and implements changes to infrastructure, data, software, and procedures to meet its objectives", + "Description": "Manages Changes Throughout the System Lifecycle - A process for managing system changes throughout the lifecycle of the system and its components (infrastructure, data, software and procedures) is used to support system availability and processing integrity. Authorizes Changes - A process is in place to authorize system changes prior to development. Designs and Develops Changes - A process is in place to design and develop system changes. Documents Changes - A process is in place to document system changes to support ongoing maintenance of the system and to support system users in performing their responsibilities. Tracks System Changes - A process is in place to track system changes prior to implementation. Configures Software - A process is in place to select and implement the configuration parameters used to control the functionality of software. Tests System Changes - A process is in place to test system changes prior to implementation. Approves System Changes - A process is in place to approve system changes prior to implementation. Deploys System Changes - A process is in place to implement system changes. Identifies and Evaluates System Changes - Objectives affected by system changes are identified, and the ability of the modified system to meet the objectives is evaluated throughout the system development life cycle. Identifies Changes in Infrastructure, Data, Software, and Procedures Required to Remediate Incidents - Changes in infrastructure, data, software, and procedures required to remediate incidents to continue to meet objectives are identified, and the change process is initiated upon identification. Creates Baseline Configuration of IT Technology - A baseline configuration of IT and control systems is created and maintained. Provides for Changes Necessary in Emergency Situations - A process is in place for authorizing, designing, testing, approving and implementing changes necessary in emergency situations (that is, changes that need to be implemented in an urgent timeframe). Protects Confidential Information - The entity protects confidential information during system design, development, testing, implementation, and change processes to meet the entity’s objectives related to confidentiality. Protects Personal Information - The entity protects personal information during system design, development, testing, implementation, and change processes to meet the entity’s objectives related to privacy.", + "Attributes": [ + { + "ItemId": "cc_8_1", + "Section": "CC8.0 - Change Management", + "Service": "monitor", + "Type": "automated" + } + ], + "Checks": [ + "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_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_diagnostic_settings_exists", + "monitor_storage_account_with_activity_logs_cmk_encrypted" + ] + }, + { + "Id": "cc_a_1_1", + "Name": "A1.2 The entity authorizes, designs, develops or acquires, implements, operates, approves, maintains, and monitors environmental protections, software, data back-up processes, and recovery infrastructure to meet its objectives", + "Description": "Measures Current Usage - The use of the system components is measured to establish a baseline for capacity management and to use when evaluating the risk of impaired availability due to capacity constraints. Forecasts Capacity - The expected average and peak use of system components is forecasted and compared to system capacity and associated tolerances. Forecasting considers capacity in the event of the failure of system components that constrain capacity. Makes Changes Based on Forecasts - The system change management process is initiated when forecasted usage exceeds capacity tolerances.", + "Attributes": [ + { + "ItemId": "cc_a_1_1", + "Section": "CCA1.0 - Additional Criterial for Availability", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "app_http_logs_enabled", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "keyvault_logging_enabled", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "mysql_flexible_server_audit_log_connection_activated", + "mysql_flexible_server_audit_log_enabled", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "postgresql_flexible_server_log_checkpoints_on", + "postgresql_flexible_server_log_connections_on", + "postgresql_flexible_server_log_disconnections_on", + "postgresql_flexible_server_log_retention_days_greater_3" + ] + }, + { + "Id": "cc_c_1_1", + "Name": "C1.1 The entity identifies and maintains confidential information to meet the entity’s objectives related to confidentiality", + "Description": "Identifies Confidential information - Procedures are in place to identify and designate confidential information when it is received or created and to determine the period over which the confidential information is to be retained. Protects Confidential Information from Destruction - Procedures are in place to protect confidential information from erasure or destruction during the specified retention period of the information", + "Attributes": [ + { + "ItemId": "cc_c_1_1", + "Section": "CCC1.0 - Additional Criterial for Confidentiality", + "Service": "storage", + "Type": "automated" + } + ], + "Checks": [ + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "cc_c_1_2", + "Name": "C1.2 The entity disposes of confidential information to meet the entity’s objectives related to confidentiality", + "Description": "Identifies Confidential Information for Destruction - Procedures are in place to identify confidential information requiring destruction when the end of the retention period is reached. Destroys Confidential Information - Procedures are in place to erase or otherwise destroy confidential information that has been identified for destruction.", + "Attributes": [ + { + "ItemId": "cc_c_1_2", + "Section": "CCC1.0 - Additional Criterial for Confidentiality", + "Service": "azure", + "Type": "automated" + } + ], + "Checks": [ + "network_flow_log_more_than_90_days", + "postgresql_flexible_server_log_retention_days_greater_3", + "sqlserver_auditing_retention_90_days", + "storage_ensure_soft_delete_is_enabled" + ] + } + ] +} From f8ee841921e0569a56d0e546e4aff1699ef6b388 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Mon, 14 Apr 2025 10:25:54 -0400 Subject: [PATCH 151/359] fix(gcp): handle projects without ID (#7496) --- prowler/providers/gcp/gcp_provider.py | 39 ++++++++++++++++++--------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/prowler/providers/gcp/gcp_provider.py b/prowler/providers/gcp/gcp_provider.py index 13e366d970..4ba25277d3 100644 --- a/prowler/providers/gcp/gcp_provider.py +++ b/prowler/providers/gcp/gcp_provider.py @@ -628,15 +628,21 @@ class GcpProvider(Provider): .get("labels", {}) .items() } - project_id = asset["resource"]["data"]["projectId"] + project_number = asset["resource"]["data"]["projectNumber"] + project_id = ( + asset["resource"]["data"].get("projectId") + if asset["resource"]["data"].get("projectId") + else project_number + ) + project_name = ( + asset["resource"]["data"].get("name") + if asset["resource"]["data"].get("name") + else project_id + ) gcp_project = GCPProject( - number=asset["resource"]["data"]["projectNumber"], + number=project_number, id=project_id, - name=( - asset["resource"]["data"].get("name") - if asset["resource"]["data"].get("name") - else project_id - ), + name=project_name, lifecycle_state=asset["resource"]["data"].get( "lifecycleState" ), @@ -677,15 +683,22 @@ class GcpProvider(Provider): labels = { k: v for k, v in project.get("labels", {}).items() } + project_number = project["projectNumber"] + project_id = ( + project.get("projectId") + if project.get("projectId") + else project_number + ) + project_name = ( + project.get("name") + if project.get("name") + else project_id + ) project_id = project["projectId"] gcp_project = GCPProject( - number=project["projectNumber"], + number=project_number, id=project_id, - name=( - project.get("name") - if project.get("name") - else project_id - ), + name=project_name, lifecycle_state=project["lifecycleState"], labels=labels, ) From 2e2a2bd89a02997b9c28e92f98adf85c7bdef872 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 14 Apr 2025 16:29:19 +0200 Subject: [PATCH 152/359] chore(regions_update): Changes in regions for AWS services (#7491) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> From abb586422437813411dd184d8e1d3aeeea6d9831 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 14 Apr 2025 21:35:46 +0545 Subject: [PATCH 153/359] chore(release): bump for 5.6.0 (#7503) --- .env | 2 +- prowler/config/config.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 82ba476870..1fa497f3e6 100644 --- a/.env +++ b/.env @@ -123,7 +123,7 @@ SENTRY_ENVIRONMENT=local SENTRY_RELEASE=local #### Prowler release version #### -NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.5.0 +NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.6.0 # Social login credentials SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google" diff --git a/prowler/config/config.py b/prowler/config/config.py index 6089a24514..2239ce4c32 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -12,7 +12,7 @@ from prowler.lib.logger import logger timestamp = datetime.today() timestamp_utc = datetime.now(timezone.utc).replace(tzinfo=timezone.utc) -prowler_version = "5.5.0" +prowler_version = "5.6.0" html_logo_url = "https://github.com/prowler-cloud/prowler/" square_logo_img = "https://prowler.com/wp-content/uploads/logo-html.png" aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png" diff --git a/pyproject.toml b/pyproject.toml index 2143b85db3..64acc1b43e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ packages = [ ] readme = "README.md" requires-python = ">3.9.1,<3.13" -version = "5.5.0" +version = "5.6.0" [project.scripts] prowler = "prowler.__main__:prowler" From 42f46b0fb1959ba719965f4fe8a869d5cb21473b Mon Sep 17 00:00:00 2001 From: Bogdan A Date: Mon, 14 Apr 2025 18:53:54 +0300 Subject: [PATCH 154/359] feat(gcp): add check for unused Service Accounts (#7419) Co-authored-by: MrCloudSec --- README.md | 2 +- prowler/compliance/gcp/mitre_attack_gcp.json | 1 + prowler/config/config.yaml | 4 + ...m_sa_user_managed_key_unused.metadata.json | 4 +- .../iam_sa_user_managed_key_unused.py | 7 +- .../providers/gcp/services/iam/iam_service.py | 2 + .../iam_service_account_unused/__init__.py | 0 .../iam_service_account_unused.metadata.json | 30 +++ .../iam_service_account_unused.py | 30 +++ .../services/monitoring/monitoring_service.py | 52 ++++- tests/config/config_test.py | 2 +- tests/config/fixtures/config.yaml | 1 + tests/providers/gcp/gcp_fixtures.py | 80 ++++++-- tests/providers/gcp/gcp_provider_test.py | 5 +- .../iam_sa_dormant_user_managed_keys_test.py | 18 +- ...am_sa_no_administrative_privileges_test.py | 8 + .../iam_sa_no_user_managed_keys_test.py | 4 + ...sa_user_managed_key_rotate_90_days_test.py | 3 + .../iam_service_account_unused_test.py | 181 ++++++++++++++++++ .../gcp/services/iam/iamgcp_service_test.py | 2 + .../monitoring/monitoring_service_test.py | 23 +++ 21 files changed, 425 insertions(+), 34 deletions(-) create mode 100644 prowler/providers/gcp/services/iam/iam_service_account_unused/__init__.py create mode 100644 prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.metadata.json create mode 100644 prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.py create mode 100644 tests/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused_test.py diff --git a/README.md b/README.md index 9922038378..2df9b00fb6 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | |---|---|---|---|---| | AWS | 564 | 82 | 33 | 10 | -| GCP | 78 | 13 | 7 | 3 | +| GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | | Microsoft365 | 5 | 2 | 1 | 0 | diff --git a/prowler/compliance/gcp/mitre_attack_gcp.json b/prowler/compliance/gcp/mitre_attack_gcp.json index 6d57c7506b..af1a68f851 100644 --- a/prowler/compliance/gcp/mitre_attack_gcp.json +++ b/prowler/compliance/gcp/mitre_attack_gcp.json @@ -145,6 +145,7 @@ "iam_sa_no_administrative_privileges", "iam_sa_no_user_managed_keys", "iam_sa_user_managed_key_rotate_90_days", + "iam_service_account_unused", "apikeys_key_rotated_in_90_days", "apikeys_api_restrictions_configured" ], diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index 2462578daa..c9b1e773bc 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -447,6 +447,10 @@ gcp: # GCP Compute Configuration # gcp.compute_public_address_shodan shodan_api_key: null + # GCP Service Account and user-managed keys unused configuration + # gcp.iam_service_account_unused + # gcp.iam_sa_user_managed_key_unused + max_unused_account_days: 180 # Kubernetes Configuration kubernetes: diff --git a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json index bc56488f9e..bdc2b7684a 100644 --- a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json +++ b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.metadata.json @@ -8,14 +8,14 @@ "ResourceIdTemplate": "", "Severity": "medium", "ResourceType": "ServiceAccountKey", - "Description": "Ensure That There Are No Dormant Service Account Keys for Each Service Account. A key is considered dormant if it has been inactive for more than 180 days.", + "Description": "Ensure That There Are No Unused Service Account Keys for Each Service Account.", "Risk": "Anyone who has access to the keys will be able to access resources through the service account. GCP-managed keys are used by Cloud Platform services such as App Engine and Compute Engine. These keys cannot be downloaded. Google will keep the keys and automatically rotate them on an approximately weekly basis. User-managed keys are created, downloadable, and managed by users.", "RelatedUrl": "https://cloud.google.com/iam/docs/service-account-overview#identify-unused", "Remediation": { "Code": { "CLI": "", "NativeIaC": "", - "Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-user-managed-service-account-keys.html", + "Other": "", "Terraform": "" }, "Recommendation": { diff --git a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py index 73e45df6bf..3c1f88fd1b 100644 --- a/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py +++ b/prowler/providers/gcp/services/iam/iam_sa_user_managed_key_unused/iam_sa_user_managed_key_unused.py @@ -8,6 +8,9 @@ from prowler.providers.gcp.services.monitoring.monitoring_client import ( class iam_sa_user_managed_key_unused(Check): def execute(self) -> Check_Report_GCP: findings = [] + max_unused_days = monitoring_client.audit_config.get( + "max_unused_account_days", 180 + ) keys_used = monitoring_client.sa_keys_metrics for account in iam_client.service_accounts: for key in account.keys: @@ -21,10 +24,10 @@ class iam_sa_user_managed_key_unused(Check): ) if key.name in keys_used: report.status = "PASS" - report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was used over the last 180 days." + report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was used over the last {max_unused_days} days." else: report.status = "FAIL" - report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was not used over the last 180 days." + report.status_extended = f"User-managed key {key.name} for Service Account {account.email} was not used over the last {max_unused_days} days." findings.append(report) return findings diff --git a/prowler/providers/gcp/services/iam/iam_service.py b/prowler/providers/gcp/services/iam/iam_service.py index d6f696d6aa..08e1ee4c3a 100644 --- a/prowler/providers/gcp/services/iam/iam_service.py +++ b/prowler/providers/gcp/services/iam/iam_service.py @@ -35,6 +35,7 @@ class IAM(GCPService): email=account["email"], display_name=account.get("displayName", ""), project_id=project_id, + uniqueId=account.get("uniqueId", ""), ) ) @@ -99,6 +100,7 @@ class ServiceAccount(BaseModel): display_name: str keys: list[Key] = [] project_id: str + uniqueId: str class AccessApproval(GCPService): diff --git a/prowler/providers/gcp/services/iam/iam_service_account_unused/__init__.py b/prowler/providers/gcp/services/iam/iam_service_account_unused/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.metadata.json b/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.metadata.json new file mode 100644 index 0000000000..6d4d889f78 --- /dev/null +++ b/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "gcp", + "CheckID": "iam_service_account_unused", + "CheckTitle": "Ensure That There Are No Unused Service Accounts", + "CheckType": [], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "ServiceAccount", + "Description": "Ensure That There Are No Unused Service Accounts.", + "Risk": "A malicious actor could make use of privilege escalation or impersonation to access an unused Service Account that is over-privileged.", + "RelatedUrl": "https://cloud.google.com/iam/docs/service-account-overview#identify-unused", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "It is recommended to disable or remove unused Service Accounts.", + "Url": "https://cloud.google.com/iam/docs/service-account-overview#identify-unused" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.py b/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.py new file mode 100644 index 0000000000..12440aff25 --- /dev/null +++ b/prowler/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused.py @@ -0,0 +1,30 @@ +from prowler.lib.check.models import Check, Check_Report_GCP +from prowler.providers.gcp.services.iam.iam_client import iam_client +from prowler.providers.gcp.services.monitoring.monitoring_client import ( + monitoring_client, +) + + +class iam_service_account_unused(Check): + def execute(self) -> Check_Report_GCP: + findings = [] + max_unused_days = monitoring_client.audit_config.get( + "max_unused_account_days", 180 + ) + sa_ids_used = monitoring_client.sa_api_metrics + for account in iam_client.service_accounts: + report = Check_Report_GCP( + metadata=self.metadata(), + resource=account, + resource_id=account.email, + location=iam_client.region, + ) + if account.uniqueId in sa_ids_used: + report.status = "PASS" + report.status_extended = f"Service Account {account.email} was used over the last {max_unused_days} days." + else: + report.status = "FAIL" + report.status_extended = f"Service Account {account.email} was not used over the last {max_unused_days} days." + findings.append(report) + + return findings diff --git a/prowler/providers/gcp/services/monitoring/monitoring_service.py b/prowler/providers/gcp/services/monitoring/monitoring_service.py index 426485c88f..575434a441 100644 --- a/prowler/providers/gcp/services/monitoring/monitoring_service.py +++ b/prowler/providers/gcp/services/monitoring/monitoring_service.py @@ -12,10 +12,12 @@ class Monitoring(GCPService): super().__init__(__class__.__name__, provider, api_version="v3") self.alert_policies = [] self.sa_keys_metrics = set() + self.sa_api_metrics = set() self._get_alert_policies() self._get_sa_keys_metrics( "iam.googleapis.com/service_account/key/authn_events_count" ) + self._get_sa_api_metrics("serviceruntime.googleapis.com/api/request_count") def _get_alert_policies(self): for project_id in self.project_ids: @@ -54,6 +56,7 @@ class Monitoring(GCPService): def _get_sa_keys_metrics(self, metric_type): try: + max_unused_days = int(self.audit_config.get("max_unused_account_days", 180)) end_time = ( datetime.datetime.now(datetime.timezone.utc) .replace(microsecond=0) @@ -62,7 +65,7 @@ class Monitoring(GCPService): start_time = ( ( datetime.datetime.now(datetime.timezone.utc) - - datetime.timedelta(days=180) + - datetime.timedelta(days=max_unused_days) ) .replace(microsecond=0) .isoformat() @@ -96,6 +99,53 @@ class Monitoring(GCPService): f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) + def _get_sa_api_metrics(self, metric_type): + try: + max_unused_days = int(self.audit_config.get("max_unused_account_days", 180)) + end_time = ( + datetime.datetime.now(datetime.timezone.utc) + .replace(microsecond=0) + .isoformat() + ) + start_time = ( + ( + datetime.datetime.now(datetime.timezone.utc) + - datetime.timedelta(days=max_unused_days) + ) + .replace(microsecond=0) + .isoformat() + ) + for project_id in self.project_ids: + try: + request = ( + self.client.projects() + .timeSeries() + .list( + name=f"projects/{project_id}", + filter=f'metric.type = "{metric_type}"', + interval_startTime=start_time, + interval_endTime=end_time, + view="HEADERS", + ) + ) + response = request.execute() + + for metric in response.get("timeSeries", []): + sa_id = metric["resource"]["labels"].get("credential_id") + if sa_id and "serviceaccount:" in sa_id: + self.sa_api_metrics.add( + sa_id.replace("serviceaccount:", "") + ) + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + class AlertPolicy(BaseModel): name: str diff --git a/tests/config/config_test.py b/tests/config/config_test.py index 0573e0c19a..d796bfde1a 100644 --- a/tests/config/config_test.py +++ b/tests/config/config_test.py @@ -324,7 +324,7 @@ config_azure = { "recommended_minimal_tls_versions": ["1.2", "1.3"], } -config_gcp = {"shodan_api_key": None} +config_gcp = {"shodan_api_key": None, "max_unused_account_days": 30} config_kubernetes = { "audit_log_maxbackup": 10, diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml index 95e8ff3332..2dc9bef561 100644 --- a/tests/config/fixtures/config.yaml +++ b/tests/config/fixtures/config.yaml @@ -399,6 +399,7 @@ gcp: # GCP Compute Configuration # gcp.compute_public_address_shodan shodan_api_key: null + max_unused_account_days: 30 # Kubernetes Configuration kubernetes: diff --git a/tests/providers/gcp/gcp_fixtures.py b/tests/providers/gcp/gcp_fixtures.py index 154b82f373..e41884d0c1 100644 --- a/tests/providers/gcp/gcp_fixtures.py +++ b/tests/providers/gcp/gcp_fixtures.py @@ -358,35 +358,73 @@ def mock_api_projects_calls(client: MagicMock): "metric": { "labels": { "key_id": "key1", - "type": "iam.googleapis.com/service_account/key/authn_events_count", }, - "resource": { - "type": "iam_service_account", - "labels": { - "project_id": "{GCP_PROJECT_ID}", - "unique_id": "111222233334444", - }, + "type": "iam.googleapis.com/service_account/key/authn_events_count", + }, + "resource": { + "type": "iam_service_account", + "labels": { + "project_id": "{GCP_PROJECT_ID}", + "unique_id": "111222233334444", }, - "metricKind": "DELTA", - "valueType": "INT64", - } + }, + "metricKind": "DELTA", + "valueType": "INT64", }, { "metric": { "labels": { "key_id": "key2", - "type": "iam.googleapis.com/service_account/key/authn_events_count", }, - "resource": { - "type": "iam_service_account", - "labels": { - "project_id": "{GCP_PROJECT_ID}", - "unique_id": "111222233334444", - }, + "type": "iam.googleapis.com/service_account/key/authn_events_count", + }, + "resource": { + "type": "iam_service_account", + "labels": { + "project_id": "{GCP_PROJECT_ID}", + "unique_id": "111222233334444", }, - "metricKind": "DELTA", - "valueType": "INT64", - } + }, + "metricKind": "DELTA", + "valueType": "INT64", + }, + { + "metric": { + "labels": { + "response_code": "200", + "protocol": "https", + }, + "type": "serviceruntime.googleapis.com/api/request_count", + }, + "resource": { + "type": "consumed_api", + "labels": { + "service": "securitycenter.googleapis.com", + "project_id": "{GCP_PROJECT_ID}", + "credential_id": "serviceaccount:111222233334444", + }, + }, + "metricKind": "DELTA", + "valueType": "INT64", + }, + { + "metric": { + "labels": { + "response_code": "200", + "protocol": "https", + }, + "type": "serviceruntime.googleapis.com/api/request_count", + }, + "resource": { + "type": "consumed_api", + "labels": { + "service": "securitycenter.googleapis.com", + "project_id": "{GCP_PROJECT_ID}", + "credential_id": "serviceaccount:55566666777888999", + }, + }, + "metricKind": "DELTA", + "valueType": "INT64", }, ] } @@ -398,11 +436,13 @@ def mock_api_projects_calls(client: MagicMock): "name": f"projects/{GCP_PROJECT_ID}/serviceAccounts/service-account1@{GCP_PROJECT_ID}.iam.gserviceaccount.com", "email": "service-account1@gmail.com", "displayName": "Service Account 1", + "uniqueId": "111222233334444", }, { "name": f"projects/{GCP_PROJECT_ID}/serviceAccounts/service-account2@{GCP_PROJECT_ID}.iam.gserviceaccount.com", "email": "service-account2@gmail.com", "displayName": "Service Account 2", + "uniqueId": "55566666777888999", }, ] } diff --git a/tests/providers/gcp/gcp_provider_test.py b/tests/providers/gcp/gcp_provider_test.py index a0096cc7fb..e3c7644f17 100644 --- a/tests/providers/gcp/gcp_provider_test.py +++ b/tests/providers/gcp/gcp_provider_test.py @@ -86,7 +86,10 @@ class TestGCPProvider: assert gcp_provider.projects == projects assert gcp_provider.default_project_id == "test-project" assert gcp_provider.identity == GCPIdentityInfo(profile="default") - assert gcp_provider.audit_config == {"shodan_api_key": None} + assert gcp_provider.audit_config == { + "shodan_api_key": None, + "max_unused_account_days": 180, + } @freeze_time(datetime.today()) def test_is_project_matching(self): diff --git a/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py b/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py index 8cb9c7c832..50a3932d6e 100644 --- a/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py +++ b/tests/providers/gcp/services/iam/iam_sa_dormant_user_managed_keys/iam_sa_dormant_user_managed_keys_test.py @@ -34,7 +34,7 @@ class Test_iam_sa_user_managed_key_unused: result = check.execute() assert len(result) == 0 - def test_iam_sa_dormant_no_keys(self): + def test_iam_sa_unused_no_keys(self): iam_client = mock.MagicMock() monitoring_client = mock.MagicMock() @@ -67,6 +67,7 @@ class Test_iam_sa_user_managed_key_unused: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -78,7 +79,7 @@ class Test_iam_sa_user_managed_key_unused: result = check.execute() assert len(result) == 0 - def test_iam_sa_dormant_system_managed_keys(self): + def test_iam_sa_unused_system_managed_keys(self): iam_client = mock.MagicMock() monitoring_client = mock.MagicMock() @@ -122,6 +123,7 @@ class Test_iam_sa_user_managed_key_unused: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -177,12 +179,14 @@ class Test_iam_sa_user_managed_key_unused: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] monitoring_client.sa_keys_metrics = set( ["90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c"] ) + monitoring_client.audit_config = {"max_unused_account_days": 30} check = iam_sa_user_managed_key_unused() result = check.execute() @@ -190,14 +194,14 @@ class Test_iam_sa_user_managed_key_unused: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"User-managed key {iam_client.service_accounts[0].keys[0].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 180 days." + == f"User-managed key {iam_client.service_accounts[0].keys[0].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 30 days." ) assert result[0].resource_id == iam_client.service_accounts[0].keys[0].name assert result[0].project_id == GCP_PROJECT_ID assert result[0].location == GCP_US_CENTER1_LOCATION assert result[0].resource_name == iam_client.service_accounts[0].email - def test_iam_sa_dormant_mixed_keys(self): + def test_iam_sa_unused_mixed_keys(self): iam_client = mock.MagicMock() monitoring_client = mock.MagicMock() @@ -255,12 +259,14 @@ class Test_iam_sa_user_managed_key_unused: ), ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] monitoring_client.sa_keys_metrics = set( ["f8e4771561be5cda9b1267add7006c5143e3a220"] ) + monitoring_client.audit_config = {"max_unused_account_days": 30} check = iam_sa_user_managed_key_unused() result = check.execute() @@ -268,7 +274,7 @@ class Test_iam_sa_user_managed_key_unused: assert result[0].status == "FAIL" assert ( result[0].status_extended - == f"User-managed key {iam_client.service_accounts[0].keys[1].name} for Service Account {iam_client.service_accounts[0].email} was not used over the last 180 days." + == f"User-managed key {iam_client.service_accounts[0].keys[1].name} for Service Account {iam_client.service_accounts[0].email} was not used over the last 30 days." ) assert result[0].resource_id == iam_client.service_accounts[0].keys[1].name assert result[0].project_id == GCP_PROJECT_ID @@ -278,7 +284,7 @@ class Test_iam_sa_user_managed_key_unused: assert result[1].status == "PASS" assert ( result[1].status_extended - == f"User-managed key {iam_client.service_accounts[0].keys[2].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 180 days." + == f"User-managed key {iam_client.service_accounts[0].keys[2].name} for Service Account {iam_client.service_accounts[0].email} was used over the last 30 days." ) assert result[1].resource_id == iam_client.service_accounts[0].keys[2].name assert result[1].project_id == GCP_PROJECT_ID diff --git a/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py b/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py index f55f8f3f10..f37d312f8a 100644 --- a/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py +++ b/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py @@ -66,6 +66,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -122,6 +123,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -187,6 +189,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -252,6 +255,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -317,6 +321,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -382,6 +387,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -447,6 +453,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -512,6 +519,7 @@ class Test_iam_sa_no_administrative_privileges: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] diff --git a/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py b/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py index 9b49a21271..2fbd41df9f 100644 --- a/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py +++ b/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py @@ -62,6 +62,7 @@ class Test_iam_sa_no_user_managed_keys: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -117,6 +118,7 @@ class Test_iam_sa_no_user_managed_keys: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -172,6 +174,7 @@ class Test_iam_sa_no_user_managed_keys: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -234,6 +237,7 @@ class Test_iam_sa_no_user_managed_keys: ), ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] diff --git a/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py b/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py index 934f4f3222..8862136463 100644 --- a/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py +++ b/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py @@ -62,6 +62,7 @@ class Test_iam_sa_user_managed_key_rotate_90_days: display_name="My service account", keys=[], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -108,6 +109,7 @@ class Test_iam_sa_user_managed_key_rotate_90_days: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] @@ -166,6 +168,7 @@ class Test_iam_sa_user_managed_key_rotate_90_days: ) ], project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", ) ] diff --git a/tests/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused_test.py b/tests/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused_test.py new file mode 100644 index 0000000000..d76200734d --- /dev/null +++ b/tests/providers/gcp/services/iam/iam_service_account_unused/iam_service_account_unused_test.py @@ -0,0 +1,181 @@ +from datetime import datetime +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import ( + GCP_PROJECT_ID, + GCP_US_CENTER1_LOCATION, + set_mocked_gcp_provider, +) + + +class Test_iam_service_account_unused: + def test_iam_no_sa(self): + iam_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused.iam_client", + new=iam_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused import ( + iam_service_account_unused, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + iam_client.service_accounts = [] + + check = iam_service_account_unused() + result = check.execute() + assert len(result) == 0 + + def test_iam_service_account_unused_single(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + from prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused import ( + iam_service_account_unused, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", + ) + ] + + monitoring_client.sa_api_metrics = set(["111222233334444"]) + monitoring_client.audit_config = {"max_unused_account_days": 30} + + check = iam_service_account_unused() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Service Account {iam_client.service_accounts[0].email} was used over the last 30 days." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource == iam_client.service_accounts[0] + + def test_iam_service_account_unused_mix(self): + iam_client = mock.MagicMock() + monitoring_client = mock.MagicMock() + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused.iam_client", + new=iam_client, + ), + mock.patch( + "prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused.monitoring_client", + new=monitoring_client, + ), + ): + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + from prowler.providers.gcp.services.iam.iam_service_account_unused.iam_service_account_unused import ( + iam_service_account_unused, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + uniqueId="111222233334444", + ), + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account2@my-project.iam.gserviceaccount.com", + email="my-service-account2@my-project.iam.gserviceaccount.com", + display_name="My service account 2", + keys=[], + project_id=GCP_PROJECT_ID, + uniqueId="55566666777888999", + ), + ] + + monitoring_client.sa_api_metrics = set(["111222233334444"]) + monitoring_client.audit_config = {"max_unused_account_days": 30} + + check = iam_service_account_unused() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Service Account {iam_client.service_accounts[0].email} was used over the last 30 days." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource == iam_client.service_accounts[0] + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == f"Service Account {iam_client.service_accounts[1].email} was not used over the last 30 days." + ) + assert result[1].resource_id == iam_client.service_accounts[1].email + assert result[1].project_id == GCP_PROJECT_ID + assert result[1].location == GCP_US_CENTER1_LOCATION + assert result[1].resource == iam_client.service_accounts[1] diff --git a/tests/providers/gcp/services/iam/iamgcp_service_test.py b/tests/providers/gcp/services/iam/iamgcp_service_test.py index 3b40b89858..c2b5e655f2 100644 --- a/tests/providers/gcp/services/iam/iamgcp_service_test.py +++ b/tests/providers/gcp/services/iam/iamgcp_service_test.py @@ -41,6 +41,7 @@ class TestIAMService: ) assert iam_client.service_accounts[0].email == "service-account1@gmail.com" assert iam_client.service_accounts[0].display_name == "Service Account 1" + assert iam_client.service_accounts[0].uniqueId == "111222233334444" assert len(iam_client.service_accounts[0].keys) == 2 assert iam_client.service_accounts[0].keys[0].name == "key1" assert iam_client.service_accounts[0].keys[0].valid_after == datetime( @@ -66,6 +67,7 @@ class TestIAMService: ) assert iam_client.service_accounts[1].email == "service-account2@gmail.com" assert iam_client.service_accounts[1].display_name == "Service Account 2" + assert iam_client.service_accounts[1].uniqueId == "55566666777888999" assert len(iam_client.service_accounts[1].keys) == 1 assert iam_client.service_accounts[1].keys[0].name == "key3" assert iam_client.service_accounts[1].keys[0].valid_after == datetime( diff --git a/tests/providers/gcp/services/monitoring/monitoring_service_test.py b/tests/providers/gcp/services/monitoring/monitoring_service_test.py index 2e3ec30637..992589649e 100644 --- a/tests/providers/gcp/services/monitoring/monitoring_service_test.py +++ b/tests/providers/gcp/services/monitoring/monitoring_service_test.py @@ -56,6 +56,7 @@ class TestMonitoringService: monitoring_client = Monitoring( set_mocked_gcp_provider(project_ids=[GCP_PROJECT_ID]) ) + monitoring_client.audit_config = {"max_unused_account_days": 30} assert monitoring_client.service == "monitoring" assert monitoring_client.project_ids == [GCP_PROJECT_ID] @@ -63,3 +64,25 @@ class TestMonitoringService: assert "key1" in monitoring_client.sa_keys_metrics assert "key2" in monitoring_client.sa_keys_metrics assert "key3" not in monitoring_client.sa_keys_metrics + + def test_sa_api_metrics(self): + with ( + patch( + "prowler.providers.gcp.lib.service.service.GCPService.__is_api_active__", + new=mock_is_api_active, + ), + patch( + "prowler.providers.gcp.lib.service.service.GCPService.__generate_client__", + new=mock_api_client, + ), + ): + monitoring_client = Monitoring( + set_mocked_gcp_provider(project_ids=[GCP_PROJECT_ID]) + ) + assert monitoring_client.service == "monitoring" + assert monitoring_client.project_ids == [GCP_PROJECT_ID] + + assert len(monitoring_client.sa_api_metrics) == 2 + assert "111222233334444" in monitoring_client.sa_api_metrics + assert "55566666777888999" in monitoring_client.sa_api_metrics + assert "0000000000000" not in monitoring_client.sa_api_metrics From d604ae5569a701f4c85c2d4b9773a603bacc4759 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 15 Apr 2025 02:35:50 +0545 Subject: [PATCH 155/359] fix(pyproject): Restore packages location (#7510) --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 64acc1b43e..b0f76fa808 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,10 +62,6 @@ description = "Prowler is an Open Source security tool to perform AWS, GCP and A license = "Apache-2.0" maintainers = [{name = "Prowler Engineering", email = "engineering@prowler.com"}] name = "prowler" -packages = [ - {include = "prowler"}, - {include = "dashboard"} -] readme = "README.md" requires-python = ">3.9.1,<3.13" version = "5.6.0" @@ -80,6 +76,10 @@ prowler = "prowler.__main__:prowler" "Issue tracker" = "https://github.com/prowler-cloud/prowler/issues" [tool.poetry] +packages = [ + {include = "prowler"}, + {include = "dashboard"} +] requires-poetry = ">=2.0" [tool.poetry.group.dev.dependencies] From 910d39eee4c5d3eebab4af27d09006db6d1d63ac Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 15 Apr 2025 01:34:50 -0400 Subject: [PATCH 156/359] chore(sdk): update changelog (#7512) --- prowler/CHANGELOG.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 3b3c514634..decb6c140d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -2,12 +2,21 @@ All notable changes to the **Prowler SDK** are documented in this file. ---- - -## [v5.5.0] +## [v5.6.0] (Prowler UNRELEASED) ### Added -### Fixed +- Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). +- Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). + +--- + +## [v5.5.1] (Prowler UNRELEASED) + +### Fixed + +- Add default name to contacts in Azure Defender [(#7483)](https://github.com/prowler-cloud/prowler/pull/7483). +- Handle projects without ID in GCP [(#7496)](https://github.com/prowler-cloud/prowler/pull/7496). +- Restore packages location in PyProject [(#7510)](https://github.com/prowler-cloud/prowler/pull/7510). --- From 25dac080a5bce737cb32087b6b28d25c0a6f38f2 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 15 Apr 2025 11:46:20 +0545 Subject: [PATCH 157/359] chore(changelog): prepare for 5.5.1 (#7523) --- .github/workflows/sdk-pull-request.yml | 1 + api/CHANGELOG.md | 2 +- prowler/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 37838feefa..2266e37baa 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -34,6 +34,7 @@ jobs: permissions/** api/** ui/** + prowler/CHANGELOG.md README.md mkdocs.yml .backportrc.json diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 46ab5ecaa6..b88fb6a2a8 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the **Prowler API** are documented in this file. -## [v1.6.1] (Prowler UNRELEASED) +## [v1.6.1] (Prowler v5.5.1) ### Changed - Changed `findings.uid` field length from `varchar(300)` to `varchar(600)` [(#7498)](https://github.com/prowler-cloud/prowler/pull/7498). diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index decb6c140d..83df480cd4 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to the **Prowler SDK** are documented in this file. --- -## [v5.5.1] (Prowler UNRELEASED) +## [v5.5.1] (Prowler v5.5.1) ### Fixed From c134914896d10ee9358c906954dd3caa0790518c Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 15 Apr 2025 15:54:32 +0545 Subject: [PATCH 158/359] revert: fix(findings): increase uid max length to 600 (#7528) --- api/CHANGELOG.md | 6 --- api/pyproject.toml | 2 +- .../api/migrations/0017_alter_finding_uid.py | 17 ------ api/src/backend/api/models.py | 2 +- api/src/backend/api/specs/v1.yaml | 4 +- api/src/backend/api/tests/test_models.py | 52 +++++++++---------- api/src/backend/api/v1/views.py | 2 +- 7 files changed, 31 insertions(+), 54 deletions(-) delete mode 100644 api/src/backend/api/migrations/0017_alter_finding_uid.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index b88fb6a2a8..44879c662a 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -2,12 +2,6 @@ All notable changes to the **Prowler API** are documented in this file. -## [v1.6.1] (Prowler v5.5.1) - -### Changed -- Changed `findings.uid` field length from `varchar(300)` to `varchar(600)` [(#7498)](https://github.com/prowler-cloud/prowler/pull/7498). - ---- ## [v1.6.0] (Prowler v5.5.0) diff --git a/api/pyproject.toml b/api/pyproject.toml index 9b9edfbac6..d8e74d6260 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -35,7 +35,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.6.1" +version = "1.6.0" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/api/migrations/0017_alter_finding_uid.py b/api/src/backend/api/migrations/0017_alter_finding_uid.py deleted file mode 100644 index 4c72d1b9a2..0000000000 --- a/api/src/backend/api/migrations/0017_alter_finding_uid.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.1.7 on 2025-04-14 06:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("api", "0016_finding_compliance_resource_details_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="finding", - name="uid", - field=models.CharField(max_length=600), - ), - ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index bede403194..69b7ead46a 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -641,7 +641,7 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel): updated_at = models.DateTimeField(auto_now=True, editable=False) first_seen_at = models.DateTimeField(editable=False, null=True) - uid = models.CharField(max_length=600) + uid = models.CharField(max_length=300) delta = FindingDeltaEnumField( choices=DeltaChoices.choices, blank=True, diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 39464648fe..30c9dbb675 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.6.1 + version: 1.6.0 description: |- Prowler API specification. @@ -6228,7 +6228,7 @@ components: properties: uid: type: string - maxLength: 600 + maxLength: 300 delta: enum: - new diff --git a/api/src/backend/api/tests/test_models.py b/api/src/backend/api/tests/test_models.py index 25ee7d9ad9..c2beeb3583 100644 --- a/api/src/backend/api/tests/test_models.py +++ b/api/src/backend/api/tests/test_models.py @@ -1,6 +1,6 @@ import pytest -from api.models import Finding, Resource, ResourceTag, StatusChoices +from api.models import Resource, ResourceTag @pytest.mark.django_db @@ -94,29 +94,29 @@ class TestResourceModel: assert resource.get_tags(tenant_id=tenant_id) == {} -@pytest.mark.django_db -class TestFindingModel: - def test_add_finding_with_long_uid( - self, providers_fixture, scans_fixture, resources_fixture - ): - provider, *_ = providers_fixture - tenant_id = provider.tenant_id +# @pytest.mark.django_db +# class TestFindingModel: +# def test_add_finding_with_long_uid( +# self, providers_fixture, scans_fixture, resources_fixture +# ): +# provider, *_ = providers_fixture +# tenant_id = provider.tenant_id - long_uid = "1" * 500 - _ = Finding.objects.create( - tenant_id=tenant_id, - uid=long_uid, - delta=Finding.DeltaChoices.NEW, - check_metadata={}, - status=StatusChoices.PASS, - status_extended="", - severity="high", - impact="high", - raw_result={}, - check_id="test_check", - scan=scans_fixture[0], - first_seen_at=None, - muted=False, - compliance={}, - ) - assert Finding.objects.filter(uid=long_uid).exists() +# long_uid = "1" * 500 +# _ = Finding.objects.create( +# tenant_id=tenant_id, +# uid=long_uid, +# delta=Finding.DeltaChoices.NEW, +# check_metadata={}, +# status=StatusChoices.PASS, +# status_extended="", +# severity="high", +# impact="high", +# raw_result={}, +# check_id="test_check", +# scan=scans_fixture[0], +# first_seen_at=None, +# muted=False, +# compliance={}, +# ) +# assert Finding.objects.filter(uid=long_uid).exists() diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 40e4c59071..e8dd81ac29 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -247,7 +247,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.6.1" + spectacular_settings.VERSION = "1.6.0" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." ) From 931766fe0896cd44b0f0bfc8bbf221971df18496 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 15 Apr 2025 18:58:26 +0545 Subject: [PATCH 159/359] chore(action): Remove cache in PyPI release (#7532) --- .github/workflows/sdk-pypi-release.yml | 4 ++-- prowler/CHANGELOG.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml index 986cee2ada..e2183909e5 100644 --- a/.github/workflows/sdk-pypi-release.yml +++ b/.github/workflows/sdk-pypi-release.yml @@ -7,7 +7,7 @@ on: env: RELEASE_TAG: ${{ github.event.release.tag_name }} PYTHON_VERSION: 3.11 - CACHE: "poetry" + # CACHE: "poetry" jobs: repository-check: @@ -74,7 +74,7 @@ jobs: uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: ${{ env.PYTHON_VERSION }} - cache: ${{ env.CACHE }} + # cache: ${{ env.CACHE }} - name: Build Prowler package run: | diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 83df480cd4..f4ff4acf68 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -9,6 +9,9 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). +### Fixed + +- Remove cache in PyPI release action [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532). --- ## [v5.5.1] (Prowler v5.5.1) From a66fa394d3f808a6764f994c1194562589806b5b Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Tue, 15 Apr 2025 15:20:20 +0200 Subject: [PATCH 160/359] chore(regions_update): Changes in regions for AWS services (#7527) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 7cd793fd7a..5811a41495 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -4184,10 +4184,12 @@ "entityresolution": { "regions": { "aws": [ + "af-south-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-west-1", "eu-west-2", @@ -9308,6 +9310,7 @@ "regions": { "aws": [ "af-south-1", + "ap-east-1", "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -9326,6 +9329,7 @@ "eu-west-1", "eu-west-2", "eu-west-3", + "il-central-1", "me-central-1", "me-south-1", "sa-east-1", @@ -11164,6 +11168,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 14ff34c00aa4e8b732736974b837eafe75e22c0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 09:25:23 -0400 Subject: [PATCH 161/359] chore(deps): bump actions/setup-node from 4.3.0 to 4.4.0 (#7521) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ui-pull-request.yml b/.github/workflows/ui-pull-request.yml index b8967c4324..5ee8f2fe6f 100644 --- a/.github/workflows/ui-pull-request.yml +++ b/.github/workflows/ui-pull-request.yml @@ -31,7 +31,7 @@ jobs: with: persist-credentials: false - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ matrix.node-version }} - name: Install dependencies From 186fd88f8c799ac953403ae0603e30bd586a39f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 09:25:44 -0400 Subject: [PATCH 162/359] chore(deps): bump codecov/codecov-action from 5.4.0 to 5.4.2 (#7522) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-pull-request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 0c8cbf5d7d..1d4733d10a 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -167,7 +167,7 @@ jobs: - name: Upload coverage reports to Codecov if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 2266e37baa..bd81c2c5c3 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -114,7 +114,7 @@ jobs: - name: Upload coverage reports to Codecov if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: From fbae338689422d82fb077249ca0619604185677b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 09:26:04 -0400 Subject: [PATCH 163/359] chore(deps): bump python from 3.12.9-alpine3.20 to 3.12.10-alpine3.20 (#7520) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02014d0203..1c19358a3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.9-alpine3.20 +FROM python:3.12.10-alpine3.20 LABEL maintainer="https://github.com/prowler-cloud/prowler" From 24dfd47329f3cadd1667a3d4d41b469bdc1986af Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 15 Apr 2025 20:01:27 +0545 Subject: [PATCH 164/359] fix(pypi): package name location in pyproject.toml while replicating for prowler-cloud (#7531) --- prowler/CHANGELOG.md | 1 + util/replicate_pypi_package.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f4ff4acf68..d77e549d8d 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. ### Fixed +- Fix package name location in pyproject.toml while replicating for prowler-cloud [(#7531)](https://github.com/prowler-cloud/prowler/pull/7531). - Remove cache in PyPI release action [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532). --- diff --git a/util/replicate_pypi_package.py b/util/replicate_pypi_package.py index f1bb552f3a..3abbdcd751 100644 --- a/util/replicate_pypi_package.py +++ b/util/replicate_pypi_package.py @@ -2,7 +2,7 @@ import toml data = toml.load("pyproject.toml") # Modify field -data["tool"]["poetry"]["name"] = "prowler-cloud" +data["project"]["name"] = "prowler-cloud" # To use the dump function, you need to open the file in 'write' mode f = open("pyproject.toml", "w") From c0d935e232b4e11f7b38f71c9d62a1c8fe03c489 Mon Sep 17 00:00:00 2001 From: Bogdan A Date: Tue, 15 Apr 2025 17:23:45 +0300 Subject: [PATCH 165/359] docs(gcp): update required permissions for GCP (#7488) --- docs/getting-started/requirements.md | 18 +++++++++++++++++- docs/tutorials/gcp/authentication.md | 19 ++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index 97ad32c5b0..53d60c6a11 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -98,7 +98,23 @@ Prowler will follow the same credentials search as [Google authentication librar 2. [User credentials set up by using the Google Cloud CLI](https://cloud.google.com/docs/authentication/application-default-credentials#personal) 3. [The attached service account, returned by the metadata server](https://cloud.google.com/docs/authentication/application-default-credentials#attached-sa) -Those credentials must be associated to a user or service account with proper permissions to do all checks. To make sure, add the `Viewer` role to the member associated with the credentials. +### Needed permissions + +Prowler for Google Cloud needs the following permissions to be set: + +- **Viewer (`roles/viewer`) IAM role**: granted at the project / folder / org level in order to scan the target projects + +- **Project level settings**: you need to have at least one project with the below settings: + - Identity and Access Management (IAM) API (`iam.googleapis.com`) enabled by either using the + [Google Cloud API UI](https://console.cloud.google.com/apis/api/iam.googleapis.com/metrics) or + by using the gcloud CLI `gcloud services enable iam.googleapis.com --project ` command + - Service Usage Consumer (`roles/serviceusage.serviceUsageConsumer`) IAM role + - Set the quota project to be this project by either running `gcloud auth application-default set-quota-project ` or by setting an environment variable: + `export GOOGLE_CLOUD_QUOTA_PROJECT=` + + +The above settings must be associated to a user or service account. + ???+ note By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned. diff --git a/docs/tutorials/gcp/authentication.md b/docs/tutorials/gcp/authentication.md index 85707a8f05..95c026decf 100644 --- a/docs/tutorials/gcp/authentication.md +++ b/docs/tutorials/gcp/authentication.md @@ -17,13 +17,22 @@ prowler gcp --credentials-file path `prowler` will scan the GCP project associated with the credentials. -Prowler will follow the same credentials search as [Google authentication libraries](https://cloud.google.com/docs/authentication/application-default-credentials#search_order): +## Needed permissions -1. [GOOGLE_APPLICATION_CREDENTIALS environment variable](https://cloud.google.com/docs/authentication/application-default-credentials#GAC) -2. [User credentials set up by using the Google Cloud CLI](https://cloud.google.com/docs/authentication/application-default-credentials#personal) -3. [The attached service account, returned by the metadata server](https://cloud.google.com/docs/authentication/application-default-credentials#attached-sa) +Prowler for Google Cloud needs the following permissions to be set: -Those credentials must be associated to a user or service account with proper permissions to do all checks. To make sure, add the `Viewer` role to the member associated with the credentials. +- **Viewer (`roles/viewer`) IAM role**: granted at the project / folder / org level in order to scan the target projects + +- **Project level settings**: you need to have at least one project with the below settings: + - Identity and Access Management (IAM) API (`iam.googleapis.com`) enabled by either using the + [Google Cloud API UI](https://console.cloud.google.com/apis/api/iam.googleapis.com/metrics) or + by using the gcloud CLI `gcloud services enable iam.googleapis.com --project ` command + - Service Usage Consumer (`roles/serviceusage.serviceUsageConsumer`) IAM role + - Set the quota project to be this project by either running `gcloud auth application-default set-quota-project ` or by setting an environment variable: + `export GOOGLE_CLOUD_QUOTA_PROJECT=` + + +The above settings must be associated to a user or service account. ???+ note Prowler will use the enabled Google Cloud APIs to get the information needed to perform the checks. From 52bd48168f460ea23758d61fbefeadd7fc8c6874 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:24:09 +0200 Subject: [PATCH 166/359] feat: adapt `Microsoft365` provider to use `PowerShell` (#7331) Co-authored-by: MrCloudSec --- README.md | 2 +- docs/developer-guide/provider.md | 2 +- docs/developer-guide/services.md | 2 +- docs/getting-started/requirements.md | 42 +- docs/index.md | 16 +- docs/tutorials/configuration_file.md | 25 +- docs/tutorials/microsoft365/authentication.md | 17 +- examples/sdk/aws_scan.ipynb | 2 +- prowler/CHANGELOG.md | 1 + prowler/__main__.py | 12 +- .../{microsoft365 => m365}/__init__.py | 0 .../cis_4.0_m365.json} | 2 +- prowler/config/config.py | 4 +- prowler/config/config.yaml | 20 +- ...xample.yaml => m365_mutelist_example.yaml} | 2 +- prowler/lib/check/models.py | 6 +- prowler/lib/cli/parser.py | 11 +- .../cis/{cis_microsoft365.py => cis_m365.py} | 8 +- prowler/lib/outputs/compliance/cis/models.py | 4 +- prowler/lib/outputs/finding.py | 2 +- prowler/lib/outputs/html/html.py | 14 +- prowler/lib/outputs/outputs.py | 2 +- prowler/lib/outputs/summary_table.py | 2 +- .../powershell}/__init__.py | 0 prowler/lib/powershell/powershell.py | 222 +++++++ prowler/providers/common/provider.py | 3 +- .../{microsoft365/lib => m365}/__init__.py | 0 .../exceptions/exceptions.py | 170 ++--- .../lib/arguments => m365/lib}/__init__.py | 0 .../lib/arguments}/__init__.py | 0 .../providers/m365/lib/arguments/arguments.py | 61 ++ .../regions => m365/lib/mutelist}/__init__.py | 0 .../lib/mutelist/mutelist.py | 6 +- .../m365/lib/powershell/m365_powershell.py | 171 ++++++ .../service => m365/lib/regions}/__init__.py | 0 .../lib/regions/regions.py | 6 +- .../lib/service}/__init__.py | 0 prowler/providers/m365/lib/service/service.py | 17 + .../m365_provider.py} | 579 +++++++++++------- .../{microsoft365 => m365}/models.py | 14 +- .../services/admincenter}/__init__.py | 0 .../admincenter/admincenter_client.py | 4 +- .../__init__.py | 0 ...groups_not_public_visibility.metadata.json | 2 +- ...dmincenter_groups_not_public_visibility.py | 10 +- .../admincenter/admincenter_service.py | 16 +- .../__init__.py | 0 ...ttings_password_never_expire.metadata.json | 2 +- ...incenter_settings_password_never_expire.py | 10 +- .../__init__.py | 0 ...ns_reduced_license_footprint.metadata.json | 2 +- ..._users_admins_reduced_license_footprint.py | 10 +- .../__init__.py | 0 ...n_two_and_four_global_admins.metadata.json | 2 +- ...sers_between_two_and_four_global_admins.py | 10 +- .../services/entra}/__init__.py | 0 .../__init__.py | 0 ...min_consent_workflow_enabled.metadata.json | 2 +- .../entra_admin_consent_workflow_enabled.py | 10 +- .../__init__.py | 0 ...n_portals_access_restriction.metadata.json | 2 +- .../entra_admin_portals_access_restriction.py | 14 +- .../entra_admin_users_cloud_only}/__init__.py | 0 ...entra_admin_users_cloud_only.metadata.json | 4 +- .../entra_admin_users_cloud_only.py | 12 +- .../__init__.py | 0 ...ntra_admin_users_mfa_enabled.metadata.json | 2 +- .../entra_admin_users_mfa_enabled.py | 14 +- .../__init__.py | 0 ...ishing_resistant_mfa_enabled.metadata.json | 2 +- ...in_users_phishing_resistant_mfa_enabled.py | 14 +- .../__init__.py | 0 ...rs_sign_in_frequency_enabled.metadata.json | 2 +- ...a_admin_users_sign_in_frequency_enabled.py | 12 +- .../services/entra/entra_client.py | 2 +- .../__init__.py | 0 ...mic_group_for_guests_created.metadata.json | 2 +- .../entra_dynamic_group_for_guests_created.py | 10 +- .../__init__.py | 0 ...tection_sign_in_risk_enabled.metadata.json | 2 +- ...dentity_protection_sign_in_risk_enabled.py | 14 +- .../__init__.py | 0 ...protection_user_risk_enabled.metadata.json | 2 +- ...a_identity_protection_user_risk_enabled.py | 14 +- .../__init__.py | 0 ...egacy_authentication_blocked.metadata.json | 2 +- .../entra_legacy_authentication_blocked.py | 14 +- .../__init__.py | 0 ..._required_for_authentication.metadata.json | 2 +- ...aged_device_required_for_authentication.py | 14 +- .../__init__.py | 0 ...equired_for_mfa_registration.metadata.json | 2 +- ...ed_device_required_for_mfa_registration.py | 14 +- .../__init__.py | 0 ...a_password_hash_sync_enabled.metadata.json | 2 +- .../entra_password_hash_sync_enabled.py | 10 +- .../__init__.py | 0 ...t_user_cannot_create_tenants.metadata.json | 2 +- ...sure_default_user_cannot_create_tenants.py | 10 +- .../__init__.py | 0 ..._invite_only_for_admin_roles.metadata.json | 2 +- ...olicy_guest_invite_only_for_admin_roles.py | 12 +- .../__init__.py | 0 ...st_users_access_restrictions.metadata.json | 2 +- ..._policy_guest_users_access_restrictions.py | 14 +- .../__init__.py | 0 ...tricts_user_consent_for_apps.metadata.json | 2 +- ..._policy_restricts_user_consent_for_apps.py | 10 +- .../services/entra/entra_service.py | 8 +- .../__init__.py | 0 ..._integrated_apps_not_allowed.metadata.json | 2 +- ..._thirdparty_integrated_apps_not_allowed.py | 10 +- .../entra_users_mfa_enabled}/__init__.py | 0 .../entra_users_mfa_enabled.metadata.json | 2 +- .../entra_users_mfa_enabled.py | 14 +- .../services/purview}/__init__.py | 0 .../__init__.py | 0 ...iew_audit_log_search_enabled.metadata.json | 30 + .../purview_audit_log_search_enabled.py | 41 ++ .../m365/services/purview/purview_client.py | 4 + .../m365/services/purview/purview_service.py | 33 + .../services/sharepoint}/__init__.py | 0 .../services/sharepoint/sharepoint_client.py | 4 +- .../__init__.py | 0 ...int_external_sharing_managed.metadata.json | 2 +- .../sharepoint_external_sharing_managed.py | 10 +- .../__init__.py | 0 ..._external_sharing_restricted.metadata.json | 2 +- .../sharepoint_external_sharing_restricted.py | 10 +- .../__init__.py | 0 ...int_guest_sharing_restricted.metadata.json | 2 +- .../sharepoint_guest_sharing_restricted.py | 10 +- .../__init__.py | 0 ...dern_authentication_required.metadata.json | 2 +- ...arepoint_modern_authentication_required.py | 10 +- .../services/sharepoint/sharepoint_service.py | 10 +- .../providers/m365/services/teams/__init__.py | 0 .../m365/services/teams/teams_client.py | 4 + .../__init__.py | 0 ...rnal_file_sharing_restricted.metadata.json | 30 + .../teams_external_file_sharing_restricted.py | 67 ++ .../m365/services/teams/teams_service.py | 45 ++ .../microsoft365/lib/arguments/arguments.py | 48 -- .../microsoft365/lib/service/service.py | 14 - tests/config/fixtures/config.yaml | 4 +- tests/lib/cli/parser_test.py | 17 +- tests/lib/outputs/finding_test.py | 6 +- tests/lib/powershell/powershell_test.py | 125 ++++ .../lib/mutelist/fixtures/m365_mutelist.yaml} | 0 .../lib/mutelist/m365_mutelist_test.py} | 18 +- .../lib/powershell/m365_powershell_test.py | 210 +++++++ .../lib/regions/m365_regions_test.py} | 16 +- .../m365_fixtures.py} | 27 +- tests/providers/m365/m365_provider_test.py | 452 ++++++++++++++ ...enter_groups_not_public_visibility_test.py | 27 +- .../admincenter/admincenter_service_test.py | 25 +- ...ter_settings_password_never_expire_test.py | 27 +- ...s_admins_reduced_license_footprint_test.py | 43 +- ...between_two_and_four_global_admins_test.py | 35 +- ...tra_admin_consent_workflow_enabled_test.py | 33 +- ...a_admin_portals_access_restriction_test.py | 37 +- .../entra_admin_users_cloud_only_test.py | 42 +- .../entra_admin_users_mfa_enabled_test.py | 55 +- ...ers_phishing_resistant_mfa_enabled_test.py | 37 +- ...in_users_sign_in_frequency_enabled_test.py | 61 +- ...a_dynamic_group_for_guests_created_test.py | 24 +- ...ty_protection_sign_in_risk_enabled_test.py | 45 +- ...ntity_protection_user_risk_enabled_test.py | 45 +- ...ntra_legacy_authentication_blocked_test.py | 37 +- ...device_required_for_authentication_test.py | 37 +- ...vice_required_for_mfa_registration_test.py | 37 +- .../entra_password_hash_sync_enabled_test.py | 30 +- ...default_user_cannot_create_tenants_test.py | 24 +- ..._guest_invite_only_for_admin_roles_test.py | 30 +- ...cy_guest_users_access_restrictions_test.py | 30 +- ...cy_restricts_user_consent_for_apps_test.py | 24 +- ...dparty_integrated_apps_not_allowed_test.py | 29 +- .../entra_users_mfa_enabled_test.py | 31 +- .../entra/microsoft365_entra_service_test.py | 37 +- .../purview_audit_log_search_enabled_test.py | 82 +++ .../services/purview/purview_service_test.py | 48 ++ ...harepoint_external_sharing_managed_test.py | 43 +- ...epoint_external_sharing_restricted_test.py | 25 +- ...harepoint_guest_sharing_restricted_test.py | 25 +- ...int_modern_authentication_required_test.py | 27 +- .../sharepoint/sharepoint_service_test.py | 17 +- ...s_external_file_sharing_restricted_test.py | 121 ++++ .../m365/services/teams/teams_service_test.py | 65 ++ .../microsoft365_provider_test.py | 312 ---------- ...ce_json_from_csv_for_cis40_microsoft365.py | 4 +- 190 files changed, 3136 insertions(+), 1569 deletions(-) rename prowler/compliance/{microsoft365 => m365}/__init__.py (100%) rename prowler/compliance/{microsoft365/cis_4.0_microsoft365.json => m365/cis_4.0_m365.json} (99%) rename prowler/config/{microsoft365_mutelist_example.yaml => m365_mutelist_example.yaml} (96%) rename prowler/lib/outputs/compliance/cis/{cis_microsoft365.py => cis_m365.py} (95%) rename prowler/{providers/microsoft365 => lib/powershell}/__init__.py (100%) create mode 100644 prowler/lib/powershell/powershell.py rename prowler/providers/{microsoft365/lib => m365}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/exceptions/exceptions.py (58%) rename prowler/providers/{microsoft365/lib/arguments => m365/lib}/__init__.py (100%) rename prowler/providers/{microsoft365/lib/mutelist => m365/lib/arguments}/__init__.py (100%) create mode 100644 prowler/providers/m365/lib/arguments/arguments.py rename prowler/providers/{microsoft365/lib/regions => m365/lib/mutelist}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/lib/mutelist/mutelist.py (74%) create mode 100644 prowler/providers/m365/lib/powershell/m365_powershell.py rename prowler/providers/{microsoft365/lib/service => m365/lib/regions}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/lib/regions/regions.py (90%) rename prowler/providers/{microsoft365/services/admincenter => m365/lib/service}/__init__.py (100%) create mode 100644 prowler/providers/m365/lib/service/service.py rename prowler/providers/{microsoft365/microsoft365_provider.py => m365/m365_provider.py} (57%) rename prowler/providers/{microsoft365 => m365}/models.py (83%) rename prowler/providers/{microsoft365/services/admincenter/admincenter_groups_not_public_visibility => m365/services/admincenter}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_client.py (53%) rename prowler/providers/{microsoft365/services/admincenter/admincenter_settings_password_never_expire => m365/services/admincenter/admincenter_groups_not_public_visibility}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py (79%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_service.py (91%) rename prowler/providers/{microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint => m365/services/admincenter/admincenter_settings_password_never_expire}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py (81%) rename prowler/providers/{microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins => m365/services/admincenter/admincenter_users_admins_reduced_license_footprint}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py (86%) rename prowler/providers/{microsoft365/services/entra => m365/services/admincenter/admincenter_users_between_two_and_four_global_admins}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py (83%) rename prowler/providers/{microsoft365/services/entra/entra_admin_consent_workflow_enabled => m365/services/entra}/__init__.py (100%) rename prowler/providers/{microsoft365/services/entra/entra_admin_portals_access_restriction => m365/services/entra/entra_admin_consent_workflow_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py (86%) rename prowler/providers/{microsoft365/services/entra/entra_admin_users_cloud_only => m365/services/entra/entra_admin_portals_access_restriction}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_admin_users_mfa_enabled => m365/services/entra/entra_admin_users_cloud_only}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json (81%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py (78%) rename prowler/providers/{microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled => m365/services/entra/entra_admin_users_mfa_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py (85%) rename prowler/providers/{microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled => m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_dynamic_group_for_guests_created => m365/services/entra/entra_admin_users_sign_in_frequency_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py (91%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_client.py (58%) rename prowler/providers/{microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled => m365/services/entra/entra_dynamic_group_for_guests_created}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_identity_protection_user_risk_enabled => m365/services/entra/entra_identity_protection_sign_in_risk_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py (86%) rename prowler/providers/{microsoft365/services/entra/entra_legacy_authentication_blocked => m365/services/entra/entra_identity_protection_user_risk_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py (86%) rename prowler/providers/{microsoft365/services/entra/entra_managed_device_required_for_authentication => m365/services/entra/entra_legacy_authentication_blocked}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_managed_device_required_for_mfa_registration => m365/services/entra/entra_managed_device_required_for_authentication}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_password_hash_sync_enabled => m365/services/entra/entra_managed_device_required_for_mfa_registration}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py (84%) rename prowler/providers/{microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants => m365/services/entra/entra_password_hash_sync_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py (82%) rename prowler/providers/{microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles => m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py (82%) rename prowler/providers/{microsoft365/services/entra/entra_policy_guest_users_access_restrictions => m365/services/entra/entra_policy_guest_invite_only_for_admin_roles}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py (80%) rename prowler/providers/{microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps => m365/services/entra/entra_policy_guest_users_access_restrictions}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py (79%) rename prowler/providers/{microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed => m365/services/entra/entra_policy_restricts_user_consent_for_apps}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py (82%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_service.py (98%) rename prowler/providers/{microsoft365/services/entra/entra_users_mfa_enabled => m365/services/entra/entra_thirdparty_integrated_apps_not_allowed}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py (83%) rename prowler/providers/{microsoft365/services/sharepoint => m365/services/entra/entra_users_mfa_enabled}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py (83%) rename prowler/providers/{microsoft365/services/sharepoint/sharepoint_external_sharing_managed => m365/services/purview}/__init__.py (100%) rename prowler/providers/{microsoft365/services/sharepoint/sharepoint_external_sharing_restricted => m365/services/purview/purview_audit_log_search_enabled}/__init__.py (100%) create mode 100644 prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.metadata.json create mode 100644 prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py create mode 100644 prowler/providers/m365/services/purview/purview_client.py create mode 100644 prowler/providers/m365/services/purview/purview_service.py rename prowler/providers/{microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted => m365/services/sharepoint}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_client.py (53%) rename prowler/providers/{microsoft365/services/sharepoint/sharepoint_modern_authentication_required => m365/services/sharepoint/sharepoint_external_sharing_managed}/__init__.py (100%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py (88%) create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/__init__.py rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py (83%) create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/__init__.py rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py (81%) create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/__init__.py rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json (98%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py (83%) rename prowler/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_service.py (85%) create mode 100644 prowler/providers/m365/services/teams/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_client.py create mode 100644 prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py create mode 100644 prowler/providers/m365/services/teams/teams_service.py delete mode 100644 prowler/providers/microsoft365/lib/arguments/arguments.py delete mode 100644 prowler/providers/microsoft365/lib/service/service.py create mode 100644 tests/lib/powershell/powershell_test.py rename tests/providers/{microsoft365/lib/mutelist/fixtures/microsoft365_mutelist.yaml => m365/lib/mutelist/fixtures/m365_mutelist.yaml} (100%) rename tests/providers/{microsoft365/lib/mutelist/microsoft365_mutelist_test.py => m365/lib/mutelist/m365_mutelist_test.py} (82%) create mode 100644 tests/providers/m365/lib/powershell/m365_powershell_test.py rename tests/providers/{microsoft365/lib/regions/microsoft365_regions_test.py => m365/lib/regions/m365_regions_test.py} (76%) rename tests/providers/{microsoft365/microsoft365_fixtures.py => m365/m365_fixtures.py} (53%) create mode 100644 tests/providers/m365/m365_provider_test.py rename tests/providers/{microsoft365 => m365}/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py (68%) rename tests/providers/{microsoft365 => m365}/services/admincenter/admincenter_service_test.py (65%) rename tests/providers/{microsoft365 => m365}/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py (69%) rename tests/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py (70%) rename tests/providers/{microsoft365 => m365}/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py (74%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py (76%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py (84%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py (82%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py (90%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py (87%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py (88%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py (72%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py (85%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py (85%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py (85%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py (83%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py (83%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py (74%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py (72%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py (75%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py (76%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py (79%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py (70%) rename tests/providers/{microsoft365 => m365}/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py (87%) rename tests/providers/{microsoft365 => m365}/services/entra/microsoft365_entra_service_test.py (88%) create mode 100644 tests/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled_test.py create mode 100644 tests/providers/m365/services/purview/purview_service_test.py rename tests/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py (78%) rename tests/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py (75%) rename tests/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py (74%) rename tests/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py (73%) rename tests/providers/{microsoft365 => m365}/services/sharepoint/sharepoint_service_test.py (66%) create mode 100644 tests/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted_test.py create mode 100644 tests/providers/m365/services/teams/teams_service_test.py delete mode 100644 tests/providers/microsoft365/microsoft365_provider_test.py diff --git a/README.md b/README.md index 2df9b00fb6..addd596590 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | -| Microsoft365 | 5 | 2 | 1 | 0 | +| M365 | 5 | 2 | 1 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | > You can list the checks, services, compliance frameworks and categories with `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`. diff --git a/docs/developer-guide/provider.md b/docs/developer-guide/provider.md index 6f6b1ca0ae..823f694a77 100644 --- a/docs/developer-guide/provider.md +++ b/docs/developer-guide/provider.md @@ -175,7 +175,7 @@ Due to the complexity and differences of each provider use the rest of the provi - [GCP](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/gcp/gcp_provider.py) - [Azure](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/azure/azure_provider.py) - [Kubernetes](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/kubernetes/kubernetes_provider.py) -- [Microsoft365](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/microsoft365/microsoft365_provider.py) +- [M365](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/m365/m365_provider.py) To facilitate understanding here is a pseudocode of how the most basic provider could be with examples. diff --git a/docs/developer-guide/services.md b/docs/developer-guide/services.md index d551a58269..6859bd0c07 100644 --- a/docs/developer-guide/services.md +++ b/docs/developer-guide/services.md @@ -237,4 +237,4 @@ It is really important to check if the current Prowler's permissions for each pr - AWS: https://docs.prowler.cloud/en/latest/getting-started/requirements/#aws-authentication - Azure: https://docs.prowler.cloud/en/latest/getting-started/requirements/#permissions - GCP: https://docs.prowler.cloud/en/latest/getting-started/requirements/#gcp-authentication -- Microsoft365: https://docs.prowler.cloud/en/latest/getting-started/requirements/#microsoft365-authentication +- M365: https://docs.prowler.cloud/en/latest/getting-started/requirements/#m365-authentication diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index 53d60c6a11..6e4ba9c267 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -40,8 +40,8 @@ If your IAM entity enforces MFA you can use `--mfa` and Prowler will ask you to Prowler for Azure supports the following authentication types. To use each one you need to pass the proper flag to the execution: -- [Service principal application](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals?tabs=browser#service-principal-object) (recommended). -- Current az cli credentials stored. +- [Service Principal Application](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals?tabs=browser#service-principal-object) (recommended). +- Current AZ CLI credentials stored. - Interactive browser authentication. - [Managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) authentication. @@ -119,12 +119,13 @@ The above settings must be associated to a user or service account. ???+ note By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned. -## Microsoft365 +## Microsoft 365 -Prowler for Microsoft365 currently supports the following authentication types: +Prowler for M365 currently supports the following authentication types: -- [Service principal application](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals?tabs=browser#service-principal-object) (recommended). -- Current az cli credentials stored. +- [Service Principal Application](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals?tabs=browser#service-principal-object). +- Service Principal Application and Microsoft User Credentials (**recommended**). +- Current AZ CLI credentials stored. - Interactive browser authentication. @@ -144,6 +145,35 @@ export AZURE_TENANT_ID="XXXXXXXXX" If you try to execute Prowler with the `--sp-env-auth` flag and those variables are empty or not exported, the execution is going to fail. Follow the instructions in the [Create Prowler Service Principal](../tutorials/azure/create-prowler-service-principal.md) section to create a service principal. +### Service Principal and User Credentials authentication (recommended) +This authentication method follows the same approach as the service principal method but introduces two additional environment variables for user credentials: `M365_USER` and `M365_ENCRYPTED_PASSWORD`. + +```console +export AZURE_CLIENT_ID="XXXXXXXXX" +export AZURE_CLIENT_SECRET="XXXXXXXXX" +export AZURE_TENANT_ID="XXXXXXXXX" +export M365_USER="your_email@example.com" +export M365_ENCRYPTED_PASSWORD="6500780061006d0070006c006500700061007300730077006f0072006400" # replace this to yours +``` + +These two new environment variables are required to execute the PowerShell modules needed to retrieve information from M365 services. Prowler will use service principal authentication to log into MS Graph and user credentials to authenticate to Microsoft PowerShell modules. + +The `M365_USER` should be your Microsoft account email, and `M365_ENCRYPTED_PASSWORD` must be an encrypted SecureString. +To convert your password into a valid encrypted string, run the following commands in PowerShell: + +```console +$securePassword = ConvertTo-SecureString "examplepassword" -AsPlainText -Force +$encryptedPassword = $securePassword | ConvertFrom-SecureString +``` + +If everything is done correctly, you will see the encrypted string that you need to set as the `M365_ENCRYPTED_PASSWORD` environment variable. +```console +Write-Output $encryptedPassword +6500780061006d0070006c006500700061007300730077006f0072006400 +``` + + + ### Interactive Browser authentication To use `--browser-auth` the user needs to authenticate against Azure using the default browser to start the scan, also `--tenant-id` flag is required. diff --git a/docs/index.md b/docs/index.md index 52c37e29cf..ac8d50461f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -170,7 +170,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), * `Python >= 3.9, <= 3.12` * `Python pip >= 21.0.0` - * AWS, GCP, Azure, Microsoft365 and/or Kubernetes credentials + * AWS, GCP, Azure, M365 and/or Kubernetes credentials _Commands_: @@ -423,7 +423,7 @@ While the scan is running, start exploring the findings in these sections: ### Prowler CLI -To run Prowler, you will need to specify the provider (e.g `aws`, `gcp`, `azure`, `microsoft365` or `kubernetes`): +To run Prowler, you will need to specify the provider (e.g `aws`, `gcp`, `azure`, `m365` or `kubernetes`): ???+ note If no provider specified, AWS will be used for backward compatibility with most of v2 options. @@ -565,23 +565,23 @@ kubectl logs prowler-XXXXX --namespace prowler-ns ???+ note By default, `prowler` will scan all namespaces in your active Kubernetes context. Use the flag `--context` to specify the context to be scanned and `--namespaces` to specify the namespaces to be scanned. -#### Microsoft365 +#### Microsoft 365 -With Microsoft365 you need to specify which auth method is going to be used: +With M365 you need to specify which auth method is going to be used: ```console # To use service principal authentication -prowler microsoft365 --sp-env-auth +prowler m365 --sp-env-auth # To use az cli authentication -prowler microsoft365 --az-cli-auth +prowler m365 --az-cli-auth # To use browser authentication -prowler microsoft365 --browser-auth --tenant-id "XXXXXXXX" +prowler m365 --browser-auth --tenant-id "XXXXXXXX" ``` -See more details about Microsoft365 Authentication in [Requirements](getting-started/requirements.md#microsoft365) +See more details about M365 Authentication in [Requirements](getting-started/requirements/#microsoft-365) ## Prowler v2 Documentation For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md). diff --git a/docs/tutorials/configuration_file.md b/docs/tutorials/configuration_file.md index 6a54e72bf2..9ee25ea7e7 100644 --- a/docs/tutorials/configuration_file.md +++ b/docs/tutorials/configuration_file.md @@ -97,14 +97,15 @@ The following list includes all the Kubernetes checks with configurable variable | `kubelet_strong_ciphers_only` | `kubelet_strong_ciphers` | String | -## Microsoft365 +## M365 ### Configurable Checks -The following list includes all the Microsoft365 checks with configurable variables that can be changed in the configuration yaml file: +The following list includes all the Microsoft 365 checks with configurable variables that can be changed in the configuration yaml file: | Check Name | Value | Type | |---------------------------------------------------------------|--------------------------------------------------|-----------------| | `entra_admin_users_sign_in_frequency_enabled` | `sign_in_frequency` | Integer | +| `teams_external_file_sharing_restricted` | `allowed_cloud_storage_services` | List of Strings | ## Config YAML File Structure @@ -504,10 +505,20 @@ kubernetes: "TLS_RSA_WITH_AES_128_GCM_SHA256", ] -# Microsoft365 Configuration -microsoft365: - # Conditional Access Policy - # policy.session_controls.sign_in_frequency.frequency in hours - sign_in_frequency: 4 +# M365 Configuration +m365: + # Entra Conditional Access Policy + # m365.entra_admin_users_sign_in_frequency_enabled + sign_in_frequency: 4 # 4 hours + # Teams Settings + # m365.teams_external_file_sharing_restricted + allowed_cloud_storage_services: + [ + #"allow_box", + #"allow_drop_box", + #"allow_egnyte", + #"allow_google_drive", + #"allow_share_file", + ] ``` diff --git a/docs/tutorials/microsoft365/authentication.md b/docs/tutorials/microsoft365/authentication.md index 750352ed76..f8bd9d13d4 100644 --- a/docs/tutorials/microsoft365/authentication.md +++ b/docs/tutorials/microsoft365/authentication.md @@ -1,23 +1,28 @@ -# Microsoft365 authentication +# Microsoft 365 authentication By default Prowler uses MsGraph Python SDK identity package authentication methods using the class `ClientSecretCredential`. -This allows Prowler to authenticate against microsoft365 using the following methods: +This allows Prowler to authenticate against Microsoft 365 using the following methods: - Service principal authentication by environment variables (Enterprise Application) +- Service principal and Microsoft user credentials by environment variabled (using PowerShell requires this authentication method) - Current CLI credentials stored - Interactive browser authentication + To launch the tool first you need to specify which method is used through the following flags: ```console +# To use service principal (app) authentication and Microsoft user credentials (to use PowerShell) +prowler m365 --env-auth + # To use service principal authentication -prowler microsoft365 --sp-env-auth +prowler m365 --sp-env-auth # To use cli authentication -prowler microsoft365 --az-cli-auth +prowler m365 --az-cli-auth # To use browser authentication -prowler microsoft365 --browser-auth --tenant-id "XXXXXXXX" +prowler m365 --browser-auth --tenant-id "XXXXXXXX" ``` -To use Prowler you need to set up also the permissions required to access your resources in your Microsoft365 account, to more details refer to [Requirements](../../getting-started/requirements.md) +To use Prowler you need to set up also the permissions required to access your resources in your Microsoft 365 account, to more details refer to [Requirements](../../getting-started/requirements.md#microsoft-365) diff --git a/examples/sdk/aws_scan.ipynb b/examples/sdk/aws_scan.ipynb index e6294a081a..f19b3ad897 100644 --- a/examples/sdk/aws_scan.ipynb +++ b/examples/sdk/aws_scan.ipynb @@ -66,7 +66,7 @@ "# from prowler.providers.gcp.gcp_provider import GcpProvider\n", "# from prowler.providers.azure.azure_provider import AzureProvider\n", "# from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider\n", - "# from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider" + "# from prowler.providers.m365.m365_provider import M365Provider" ] }, { diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index d77e549d8d..441ca9979a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). +- Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) ### Fixed diff --git a/prowler/__main__.py b/prowler/__main__.py index f7e617ebcc..3bacaf291f 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -51,7 +51,7 @@ 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_kubernetes import KubernetesCIS -from prowler.lib.outputs.compliance.cis.cis_microsoft365 import Microsoft365CIS +from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.compliance import display_compliance_table from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS @@ -85,7 +85,7 @@ from prowler.providers.common.provider import Provider from prowler.providers.common.quick_inventory import run_provider_quick_inventory from prowler.providers.gcp.models import GCPOutputOptions from prowler.providers.kubernetes.models import KubernetesOutputOptions -from prowler.providers.microsoft365.models import Microsoft365OutputOptions +from prowler.providers.m365.models import M365OutputOptions from prowler.providers.nhn.models import NHNOutputOptions @@ -268,8 +268,8 @@ def prowler(): output_options = KubernetesOutputOptions( args, bulk_checks_metadata, global_provider.identity ) - elif provider == "microsoft365": - output_options = Microsoft365OutputOptions( + elif provider == "m365": + output_options = M365OutputOptions( args, bulk_checks_metadata, global_provider.identity ) elif provider == "nhn": @@ -666,7 +666,7 @@ def prowler(): generated_outputs["compliance"].append(generic_compliance) generic_compliance.batch_write_data_to_file() - elif provider == "microsoft365": + elif provider == "m365": for compliance_name in input_compliance_frameworks: if compliance_name.startswith("cis_"): # Generate CIS Finding Object @@ -674,7 +674,7 @@ def prowler(): f"{output_options.output_directory}/compliance/" f"{output_options.output_filename}_{compliance_name}.csv" ) - cis = Microsoft365CIS( + cis = M365CIS( findings=finding_outputs, compliance=bulk_compliance_frameworks[compliance_name], file_path=filename, diff --git a/prowler/compliance/microsoft365/__init__.py b/prowler/compliance/m365/__init__.py similarity index 100% rename from prowler/compliance/microsoft365/__init__.py rename to prowler/compliance/m365/__init__.py diff --git a/prowler/compliance/microsoft365/cis_4.0_microsoft365.json b/prowler/compliance/m365/cis_4.0_m365.json similarity index 99% rename from prowler/compliance/microsoft365/cis_4.0_microsoft365.json rename to prowler/compliance/m365/cis_4.0_m365.json index ca26b4a467..a85f8a953d 100644 --- a/prowler/compliance/microsoft365/cis_4.0_microsoft365.json +++ b/prowler/compliance/m365/cis_4.0_m365.json @@ -1,7 +1,7 @@ { "Framework": "CIS", "Version": "4.0", - "Provider": "Microsoft365", + "Provider": "M365", "Description": "The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for establishing a secure configuration posture for Microsoft 365 Cloud offerings running on any OS.", "Requirements": [ { diff --git a/prowler/config/config.py b/prowler/config/config.py index 2239ce4c32..38d0134859 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -28,7 +28,7 @@ class Provider(str, Enum): GCP = "gcp" AZURE = "azure" KUBERNETES = "kubernetes" - MICROSOFT365 = "microsoft365" + M365 = "m365" NHN = "nhn" @@ -126,7 +126,7 @@ def load_and_validate_config_file(provider: str, config_file_path: str) -> dict: # and a new format with a key for each provider to include their configuration values within. if any( key in config_file - for key in ["aws", "gcp", "azure", "kubernetes", "microsoft365"] + for key in ["aws", "gcp", "azure", "kubernetes", "m365"] ): config = config_file.get(provider, {}) else: diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index c9b1e773bc..c8a2ee7e50 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -483,8 +483,18 @@ kubernetes: ] -# Microsoft365 Configuration -microsoft365: - # Conditional Access Policy - # policy.session_controls.sign_in_frequency.frequency in hours - sign_in_frequency: 4 +# M365 Configuration +m365: + # Entra Conditional Access Policy + # m365.entra_admin_users_sign_in_frequency_enabled + sign_in_frequency: 4 # 4 hours + # Teams Settings + # m365.teams_external_file_sharing_restricted + allowed_cloud_storage_services: + [ + #"allow_box", + #"allow_drop_box", + #"allow_egnyte", + #"allow_google_drive", + #"allow_share_file", + ] diff --git a/prowler/config/microsoft365_mutelist_example.yaml b/prowler/config/m365_mutelist_example.yaml similarity index 96% rename from prowler/config/microsoft365_mutelist_example.yaml rename to prowler/config/m365_mutelist_example.yaml index c33b442c04..34fda956e0 100644 --- a/prowler/config/microsoft365_mutelist_example.yaml +++ b/prowler/config/m365_mutelist_example.yaml @@ -1,5 +1,5 @@ ### Account, Check and/or Region can be * to apply for all the cases. -### Account == Microsoft365 Tenant and Region == Microsoft365 Location +### Account == M365 Tenant and Region == M365 Location ### Resources and tags are lists that can have either Regex or Keywords. ### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together. ### Use an alternation Regex to match one of multiple tags with "ORed" logic. diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index b76424f495..88e4d83aa7 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -543,8 +543,8 @@ class Check_Report_Kubernetes(Check_Report): @dataclass -class CheckReportMicrosoft365(Check_Report): - """Contains the Microsoft365 Check's finding information.""" +class CheckReportM365(Check_Report): + """Contains the M365 Check's finding information.""" resource_name: str resource_id: str @@ -558,7 +558,7 @@ class CheckReportMicrosoft365(Check_Report): resource_id: str, resource_location: str = "global", ) -> None: - """Initialize the Microsoft365 Check's finding information. + """Initialize the M365 Check's finding information. Args: metadata: The metadata of the check. diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index 0a5f63074d..f2cc8d12dd 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -26,15 +26,15 @@ class ProwlerArgumentParser: self.parser = argparse.ArgumentParser( prog="prowler", formatter_class=RawTextHelpFormatter, - usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,nhn,dashboard} ...", + usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,nhn,dashboard} ...", epilog=""" Available Cloud Providers: - {aws,azure,gcp,kubernetes,microsoft365,nhn} + {aws,azure,gcp,kubernetes,m365,nhn} aws AWS Provider azure Azure Provider gcp GCP Provider kubernetes Kubernetes Provider - microsoft365 Microsoft 365 Provider + m365 Microsoft 365 Provider nhn NHN Provider (Unofficial) Available components: @@ -104,6 +104,11 @@ Detailed documentation at https://docs.prowler.com if "-" in sys.argv[1]: sys.argv = self.__set_default_provider__(sys.argv) + # Provider aliases mapping + # Microsoft 365 + elif sys.argv[1] == "microsoft365": + sys.argv[1] = "m365" + # Parse arguments args = self.parser.parse_args() diff --git a/prowler/lib/outputs/compliance/cis/cis_microsoft365.py b/prowler/lib/outputs/compliance/cis/cis_m365.py similarity index 95% rename from prowler/lib/outputs/compliance/cis/cis_microsoft365.py rename to prowler/lib/outputs/compliance/cis/cis_m365.py index 8cf4722ba7..a587d98214 100644 --- a/prowler/lib/outputs/compliance/cis/cis_microsoft365.py +++ b/prowler/lib/outputs/compliance/cis/cis_m365.py @@ -1,10 +1,10 @@ from prowler.lib.check.compliance_models import Compliance -from prowler.lib.outputs.compliance.cis.models import Microsoft365CISModel +from prowler.lib.outputs.compliance.cis.models import M365CISModel from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput from prowler.lib.outputs.finding import Finding -class Microsoft365CIS(ComplianceOutput): +class M365CIS(ComplianceOutput): """ This class represents the Azure CIS compliance output. @@ -39,7 +39,7 @@ class Microsoft365CIS(ComplianceOutput): for requirement in compliance.Requirements: if requirement.Id in finding_requirements: for attribute in requirement.Attributes: - compliance_row = Microsoft365CISModel( + compliance_row = M365CISModel( Provider=finding.provider, Description=compliance.Description, TenantId=finding.account_uid, @@ -70,7 +70,7 @@ class Microsoft365CIS(ComplianceOutput): for requirement in compliance.Requirements: if not requirement.Checks: for attribute in requirement.Attributes: - compliance_row = Microsoft365CISModel( + compliance_row = M365CISModel( Provider=compliance.Provider.lower(), Description=compliance.Description, TenantId=finding.account_uid, diff --git a/prowler/lib/outputs/compliance/cis/models.py b/prowler/lib/outputs/compliance/cis/models.py index 1f6e661655..201925f19d 100644 --- a/prowler/lib/outputs/compliance/cis/models.py +++ b/prowler/lib/outputs/compliance/cis/models.py @@ -69,9 +69,9 @@ class AzureCISModel(BaseModel): Muted: bool -class Microsoft365CISModel(BaseModel): +class M365CISModel(BaseModel): """ - Microsoft365CISModel generates a finding's output in Microsoft365 CIS Compliance format. + M365CISModel generates a finding's output in Microsoft 365 CIS Compliance format. """ Provider: str diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index b1c8299887..f8aab16555 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -245,7 +245,7 @@ class Finding(BaseModel): ) output_data["region"] = f"namespace: {check_output.namespace}" - elif provider.type == "microsoft365": + elif provider.type == "m365": output_data["auth_method"] = ( f"{provider.identity.identity_type}: {provider.identity.identity_id}" ) diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index 8e3c88efd6..d9177a4ab9 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -546,9 +546,9 @@ class HTML(Output): return "" @staticmethod - def get_microsoft365_assessment_summary(provider: Provider) -> str: + def get_m365_assessment_summary(provider: Provider) -> str: """ - get_microsoft365_assessment_summary gets the HTML assessment summary for the provider + get_m365_assessment_summary gets the HTML assessment summary for the provider Args: provider (Provider): the provider object @@ -561,11 +561,11 @@ class HTML(Output):
    - Microsoft365 Assessment Summary + M365 Assessment Summary
    • - Microsoft365 Tenant Domain: {provider.identity.tenant_domain} + M365 Tenant Domain: {provider.identity.tenant_domain}
    @@ -573,14 +573,14 @@ class HTML(Output):
    - Microsoft365 Credentials + M365 Credentials
    • - Microsoft365 Identity Type: {provider.identity.identity_type} + M365 Identity Type: {provider.identity.identity_type}
    • - Microsoft365 Identity ID: {provider.identity.identity_id} + M365 Identity ID: {provider.identity.identity_id}
    diff --git a/prowler/lib/outputs/outputs.py b/prowler/lib/outputs/outputs.py index 0912f986af..bb635510ac 100644 --- a/prowler/lib/outputs/outputs.py +++ b/prowler/lib/outputs/outputs.py @@ -16,7 +16,7 @@ def stdout_report(finding, color, verbose, status, fix): details = finding.location.lower() if finding.check_metadata.Provider == "kubernetes": details = finding.namespace.lower() - if finding.check_metadata.Provider == "microsoft365": + if finding.check_metadata.Provider == "m365": details = finding.location if finding.check_metadata.Provider == "nhn": details = finding.location diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index b860285e2e..8d8dbc0e95 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -40,7 +40,7 @@ def display_summary_table( elif provider.type == "kubernetes": entity_type = "Context" audited_entities = provider.identity.context - elif provider.type == "microsoft365": + elif provider.type == "m365": entity_type = "Tenant Domain" audited_entities = provider.identity.tenant_domain elif provider.type == "nhn": diff --git a/prowler/providers/microsoft365/__init__.py b/prowler/lib/powershell/__init__.py similarity index 100% rename from prowler/providers/microsoft365/__init__.py rename to prowler/lib/powershell/__init__.py diff --git a/prowler/lib/powershell/powershell.py b/prowler/lib/powershell/powershell.py new file mode 100644 index 0000000000..373fc97183 --- /dev/null +++ b/prowler/lib/powershell/powershell.py @@ -0,0 +1,222 @@ +import json +import platform +import queue +import re +import subprocess +import threading + + +class PowerShellSession: + """ + Base class for managing PowerShell sessions. + + This class provides the core functionality for interacting with PowerShell, + including command execution, output handling, and session management. + It serves as a foundation for more specific PowerShell implementations. + + Features: + - Maintains a persistent PowerShell session + - Handles command execution and output parsing + - Provides secure input sanitization + - Manages ANSI escape sequence removal + - Supports JSON output parsing + - Implements timeout handling for long-running commands + + Attributes: + END (str): Marker string used to signal the end of PowerShell command output. + process (subprocess.Popen): The underlying PowerShell subprocess with open stdin, stdout, and stderr streams. + + Note: + This is an abstract base class that should be extended by specific implementations + for different PowerShell use cases. + """ + + END = "" + + def __init__(self): + """ + Initialize a persistent PowerShell session. + + Creates a subprocess running PowerShell with pipes for stdin, stdout, and stderr. + The session is configured to run in interactive mode with no exit. + + Note: + This is a base implementation that should be extended by subclasses + to add specific initialization logic (e.g., credential setup). + """ + # Determine the appropriate PowerShell command based on the OS + if platform.system() == "Windows": + powershell_cmd = "powershell" + else: + powershell_cmd = "pwsh" + + self.process = subprocess.Popen( + [powershell_cmd, "-NoExit", "-Command", "-"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1, + ) + + def sanitize(self, credential: str) -> str: + """ + Sanitize input to prevent command injection. + + Filters the input string to allow only letters, numbers, @, periods, underscores, + plus signs, and hyphens. This is a security measure to prevent command injection + attacks through credential input. + + Args: + credential (str): The string to sanitize. + + Returns: + str: The sanitized string containing only allowed characters. + + Example: + >>> sanitize("user@domain.com!@#$") + "user@domain.com" + """ + return re.sub(r"[^a-zA-Z0-9@._+\-]", "", credential) + + def remove_ansi(self, text: str) -> str: + """ + Remove ANSI color codes and other escape sequences from PowerShell output. + + PowerShell often includes ANSI escape sequences in its output for terminal + coloring and formatting. This method strips these sequences to produce clean, + parseable text that can be processed programmatically. + + Args: + text (str): Raw text containing ANSI escape sequences from PowerShell output. + + Returns: + str: Clean text with all ANSI escape sequences removed, suitable for parsing. + + Example: + >>> remove_ansi("\x1b[32mSuccess\x1b[0m") + "Success" + """ + ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") + return ansi_escape.sub("", text) + + def execute(self, command: str) -> dict: + """ + Send a command to PowerShell and retrieve its output. + + Executes the given command in the PowerShell session, adds an END marker, + and parses the output as JSON if possible. The command is executed + asynchronously with a timeout mechanism. + + Args: + command (str): PowerShell command to execute. + + Returns: + dict: JSON-parsed output if available, otherwise an empty dictionary. + + Example: + >>> execute("Get-Process | ConvertTo-Json") + {"Name": "process1", "Id": 1234} + """ + self.process.stdin.write(f"{command}\n") + self.process.stdin.write(f"Write-Output '{self.END}'\n") + return self.json_parse_output(self.read_output()) + + def read_output(self, timeout: int = 10, default: str = "") -> str: + """ + Read output from a process with timeout functionality. + + This method reads lines from process stdout until it encounters the END marker + or the stream ends. If reading takes longer than the timeout period, the method + returns a default value while allowing the reading to continue in the background. + + Args: + timeout (int, optional): Maximum time in seconds to wait for output. + Defaults to 10. + default (str, optional): Value to return if timeout occurs. + Defaults to empty string. + + Returns: + str: Concatenated output lines or default value if timeout occurs. + + Note: + This method uses a daemon thread to read the output asynchronously, + ensuring that the main thread is not blocked. + """ + output_lines = [] + result_queue = queue.Queue() + + def reader_thread(): + try: + while True: + line = self.remove_ansi(self.process.stdout.readline().strip()) + if line == self.END: + break + output_lines.append(line) + result_queue.put("\n".join(output_lines)) + except Exception as e: + result_queue.put(str(e)) + + thread = threading.Thread(target=reader_thread) + thread.daemon = True + thread.start() + + try: + return result_queue.get(timeout=timeout) + except queue.Empty: + return default + + def json_parse_output(self, output: str) -> dict: + """ + Parse command execution output to JSON format. + + Searches for a JSON object in the output string and parses it. + The method looks for both object and array JSON structures. + + Args: + output (str): The string output from a PowerShell command. + + Returns: + dict: Parsed JSON object if found, otherwise an empty dictionary. + + Example: + >>> json_parse_output('Some text {"key": "value"} more text') + {"key": "value"} + """ + json_match = re.search(r"(\[.*\]|\{.*\})", output, re.DOTALL) + if json_match: + return json.loads(json_match.group(1)) + return {} + + def close(self) -> None: + """ + Terminate the PowerShell session. + + Sends an exit command to PowerShell and terminates the subprocess. + This method should be called when the session is no longer needed + to ensure proper cleanup of resources. + + Note: + It's important to call this method when done with the session + to prevent resource leaks. + """ + if self.process: + try: + # Send exit command + self.process.stdin.write("exit\n") + self.process.stdin.flush() + + # Terminate the process + self.process.terminate() + + # Wait for the process to finish + self.process.wait(timeout=5) + except Exception: + # If process is still running, force kill it + self.process.kill() + finally: + # Close all pipes + self.process.stdin.close() + self.process.stdout.close() + self.process.stderr.close() + self.process = None diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index b8fe46d9e8..0efde909ef 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -211,12 +211,13 @@ class Provider(ABC): mutelist_path=arguments.mutelist_file, fixer_config=fixer_config, ) - elif "microsoft365" in provider_class_name.lower(): + elif "m365" in provider_class_name.lower(): provider_class( region=arguments.region, config_path=arguments.config_file, mutelist_path=arguments.mutelist_file, sp_env_auth=arguments.sp_env_auth, + env_auth=arguments.env_auth, az_cli_auth=arguments.az_cli_auth, browser_auth=arguments.browser_auth, tenant_id=arguments.tenant_id, diff --git a/prowler/providers/microsoft365/lib/__init__.py b/prowler/providers/m365/__init__.py similarity index 100% rename from prowler/providers/microsoft365/lib/__init__.py rename to prowler/providers/m365/__init__.py diff --git a/prowler/providers/microsoft365/exceptions/exceptions.py b/prowler/providers/m365/exceptions/exceptions.py similarity index 58% rename from prowler/providers/microsoft365/exceptions/exceptions.py rename to prowler/providers/m365/exceptions/exceptions.py index 45c645802d..9f9c96a178 100644 --- a/prowler/providers/microsoft365/exceptions/exceptions.py +++ b/prowler/providers/m365/exceptions/exceptions.py @@ -1,103 +1,111 @@ from prowler.exceptions.exceptions import ProwlerException -# Exceptions codes from 5000 to 5999 are reserved for Microsoft365 exceptions -class Microsoft365BaseException(ProwlerException): - """Base class for Microsoft365 Errors.""" +# Exceptions codes from 5000 to 5999 are reserved for M365 exceptions +class M365BaseException(ProwlerException): + """Base class for M365 Errors.""" MICROSOFT365_ERROR_CODES = { - (6000, "Microsoft365EnvironmentVariableError"): { - "message": "Microsoft365 environment variable error", - "remediation": "Check the Microsoft365 environment variables and ensure they are properly set.", + (6000, "M365EnvironmentVariableError"): { + "message": "Microsoft 365 environment variable error", + "remediation": "Check the Microsoft 365 environment variables and ensure they are properly set.", }, - (6001, "Microsoft365ArgumentTypeValidationError"): { - "message": "Microsoft365 argument type validation error", - "remediation": "Check the provided argument types specific to Microsoft365 and ensure they meet the required format.", + (6001, "M365ArgumentTypeValidationError"): { + "message": "Microsoft 365 argument type validation error", + "remediation": "Check the provided argument types specific to Microsoft 365 and ensure they meet the required format.", }, - (6002, "Microsoft365SetUpRegionConfigError"): { - "message": "Microsoft365 region configuration setup error", - "remediation": "Check the Microsoft365 region configuration and ensure it is properly set up.", + (6002, "M365SetUpRegionConfigError"): { + "message": "Microsoft 365 region configuration setup error", + "remediation": "Check the Microsoft 365 region configuration and ensure it is properly set up.", }, - (6003, "Microsoft365HTTPResponseError"): { - "message": "Error in HTTP response from Microsoft365", + (6003, "M365HTTPResponseError"): { + "message": "Error in HTTP response from Microsoft 365", "remediation": "", }, - (6004, "Microsoft365CredentialsUnavailableError"): { - "message": "Error trying to configure Microsoft365 credentials because they are unavailable", - "remediation": "Check the dictionary and ensure it is properly set up for Microsoft365 credentials. TENANT_ID, CLIENT_ID and CLIENT_SECRET are required.", + (6004, "M365CredentialsUnavailableError"): { + "message": "Error trying to configure Microsoft 365 credentials because they are unavailable", + "remediation": "Check the dictionary and ensure it is properly set up for Microsoft 365 credentials. TENANT_ID, CLIENT_ID and CLIENT_SECRET are required.", }, - (6005, "Microsoft365GetTokenIdentityError"): { - "message": "Error trying to get token from Microsoft365 Identity", - "remediation": "Check the Microsoft365 Identity and ensure it is properly set up.", + (6005, "M365GetTokenIdentityError"): { + "message": "Error trying to get token from Microsoft 365 Identity", + "remediation": "Check the Microsoft 365 Identity and ensure it is properly set up.", }, - (6006, "Microsoft365ClientAuthenticationError"): { + (6006, "M365ClientAuthenticationError"): { "message": "Error in client authentication", "remediation": "Check the client authentication and ensure it is properly set up.", }, - (6007, "Microsoft365NotValidTenantIdError"): { + (6007, "M365NotValidTenantIdError"): { "message": "The provided tenant ID is not valid", "remediation": "Check the tenant ID and ensure it is a valid ID.", }, - (6008, "Microsoft365NotValidClientIdError"): { + (6008, "M365NotValidClientIdError"): { "message": "The provided client ID is not valid", "remediation": "Check the client ID and ensure it is a valid ID.", }, - (6009, "Microsoft365NotValidClientSecretError"): { + (6009, "M365NotValidClientSecretError"): { "message": "The provided client secret is not valid", "remediation": "Check the client secret and ensure it is a valid secret.", }, - (6010, "Microsoft365ConfigCredentialsError"): { - "message": "Error in configuration of Microsoft365 credentials", - "remediation": "Check the configuration of Microsoft365 credentials and ensure it is properly set up.", + (6010, "M365ConfigCredentialsError"): { + "message": "Error in configuration of Microsoft 365 credentials", + "remediation": "Check the configuration of Microsoft 365 credentials and ensure it is properly set up.", }, - (6011, "Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError"): { + (6011, "M365ClientIdAndClientSecretNotBelongingToTenantIdError"): { "message": "The provided client ID and client secret do not belong to the provided tenant ID", "remediation": "Check the client ID and client secret and ensure they belong to the provided tenant ID.", }, - (6012, "Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError"): { + (6012, "M365TenantIdAndClientSecretNotBelongingToClientIdError"): { "message": "The provided tenant ID and client secret do not belong to the provided client ID", "remediation": "Check the tenant ID and client secret and ensure they belong to the provided client ID.", }, - (6013, "Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError"): { + (6013, "M365TenantIdAndClientIdNotBelongingToClientSecretError"): { "message": "The provided tenant ID and client ID do not belong to the provided client secret", "remediation": "Check the tenant ID and client ID and ensure they belong to the provided client secret.", }, - (6014, "Microsoft365InvalidProviderIdError"): { + (6014, "M365InvalidProviderIdError"): { "message": "The provided provider_id does not match with the available subscriptions", "remediation": "Check the provider_id and ensure it is a valid subscription for the given credentials.", }, - (6015, "Microsoft365NoAuthenticationMethodError"): { - "message": "No Microsoft365 authentication method found", - "remediation": "Check that any authentication method is properly set up for Microsoft365.", + (6015, "M365NoAuthenticationMethodError"): { + "message": "No Microsoft 365 authentication method found", + "remediation": "Check that any authentication method is properly set up for Microsoft 365.", }, - (6016, "Microsoft365SetUpSessionError"): { + (6016, "M365SetUpSessionError"): { "message": "Error setting up session", "remediation": "Check the session setup and ensure it is properly set up.", }, - (6017, "Microsoft365DefaultAzureCredentialError"): { + (6017, "M365DefaultAzureCredentialError"): { "message": "Error with DefaultAzureCredential", "remediation": "Ensure DefaultAzureCredential is correctly configured.", }, - (6018, "Microsoft365InteractiveBrowserCredentialError"): { + (6018, "M365InteractiveBrowserCredentialError"): { "message": "Error with InteractiveBrowserCredential", "remediation": "Ensure InteractiveBrowserCredential is correctly configured.", }, - (6019, "Microsoft365BrowserAuthNoTenantIDError"): { - "message": "Microsoft365 Tenant ID (--tenant-id) is required for browser authentication mode", - "remediation": "Check the Microsoft365 Tenant ID and ensure it is properly set up.", + (6019, "M365BrowserAuthNoTenantIDError"): { + "message": "Microsoft 365 Tenant ID (--tenant-id) is required for browser authentication mode", + "remediation": "Check the Microsoft 365 Tenant ID and ensure it is properly set up.", }, - (6020, "Microsoft365BrowserAuthNoFlagError"): { - "message": "Microsoft365 tenant ID error: browser authentication flag (--browser-auth) not found", + (6020, "M365BrowserAuthNoFlagError"): { + "message": "Microsoft 365 tenant ID error: browser authentication flag (--browser-auth) not found", "remediation": "To use browser authentication, ensure the tenant ID is properly set.", }, - (6021, "Microsoft365NotTenantIdButClientIdAndClientSecretError"): { - "message": "Tenant Id is required for Microsoft365 static credentials. Make sure you are using the correct credentials.", - "remediation": "Check the Microsoft365 Tenant ID and ensure it is properly set up.", + (6021, "M365NotTenantIdButClientIdAndClientSecretError"): { + "message": "Tenant Id is required for Microsoft 365 static credentials. Make sure you are using the correct credentials.", + "remediation": "Check the Microsoft 365 Tenant ID and ensure it is properly set up.", + }, + (6022, "M365MissingEnvironmentUserCredentialsError"): { + "message": "User and Password environment variables are needed to use Credentials authentication method.", + "remediation": "Ensure your environment variables are properly set up.", + }, + (6023, "M365EnvironmentUserCredentialsError"): { + "message": "User or Password environment variables are not correct.", + "remediation": "Ensure you are using the right credentials.", }, } def __init__(self, code, file=None, original_exception=None, message=None): - provider = "Microsoft365" + provider = "M365" error_info = self.MICROSOFT365_ERROR_CODES.get((code, self.__class__.__name__)) if message: error_info["message"] = message @@ -110,170 +118,176 @@ class Microsoft365BaseException(ProwlerException): ) -class Microsoft365CredentialsError(Microsoft365BaseException): - """Base class for Microsoft365 credentials errors.""" +class M365CredentialsError(M365BaseException): + """Base class for M365 credentials errors.""" def __init__(self, code, file=None, original_exception=None, message=None): super().__init__(code, file, original_exception, message) -class Microsoft365EnvironmentVariableError(Microsoft365CredentialsError): +class M365EnvironmentVariableError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6000, file=file, original_exception=original_exception, message=message ) -class Microsoft365ArgumentTypeValidationError(Microsoft365BaseException): +class M365ArgumentTypeValidationError(M365BaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6001, file=file, original_exception=original_exception, message=message ) -class Microsoft365SetUpRegionConfigError(Microsoft365BaseException): +class M365SetUpRegionConfigError(M365BaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6002, file=file, original_exception=original_exception, message=message ) -class Microsoft365HTTPResponseError(Microsoft365BaseException): +class M365HTTPResponseError(M365BaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6003, file=file, original_exception=original_exception, message=message ) -class Microsoft365CredentialsUnavailableError(Microsoft365CredentialsError): +class M365CredentialsUnavailableError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6004, file=file, original_exception=original_exception, message=message ) -class Microsoft365GetTokenIdentityError(Microsoft365BaseException): +class M365GetTokenIdentityError(M365BaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6005, file=file, original_exception=original_exception, message=message ) -class Microsoft365ClientAuthenticationError(Microsoft365CredentialsError): +class M365ClientAuthenticationError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6006, file=file, original_exception=original_exception, message=message ) -class Microsoft365NotValidTenantIdError(Microsoft365CredentialsError): +class M365NotValidTenantIdError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6007, file=file, original_exception=original_exception, message=message ) -class Microsoft365NotValidClientIdError(Microsoft365CredentialsError): +class M365NotValidClientIdError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6008, file=file, original_exception=original_exception, message=message ) -class Microsoft365NotValidClientSecretError(Microsoft365CredentialsError): +class M365NotValidClientSecretError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6009, file=file, original_exception=original_exception, message=message ) -class Microsoft365ConfigCredentialsError(Microsoft365CredentialsError): +class M365ConfigCredentialsError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6010, file=file, original_exception=original_exception, message=message ) -class Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError( - Microsoft365CredentialsError -): +class M365ClientIdAndClientSecretNotBelongingToTenantIdError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6011, file=file, original_exception=original_exception, message=message ) -class Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError( - Microsoft365CredentialsError -): +class M365TenantIdAndClientSecretNotBelongingToClientIdError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6012, file=file, original_exception=original_exception, message=message ) -class Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError( - Microsoft365CredentialsError -): +class M365TenantIdAndClientIdNotBelongingToClientSecretError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6013, file=file, original_exception=original_exception, message=message ) -class Microsoft365InvalidProviderIdError(Microsoft365BaseException): +class M365InvalidProviderIdError(M365BaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6014, file=file, original_exception=original_exception, message=message ) -class Microsoft365NoAuthenticationMethodError(Microsoft365CredentialsError): +class M365NoAuthenticationMethodError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6015, file=file, original_exception=original_exception, message=message ) -class Microsoft365SetUpSessionError(Microsoft365CredentialsError): +class M365SetUpSessionError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6016, file=file, original_exception=original_exception, message=message ) -class Microsoft365DefaultAzureCredentialError(Microsoft365CredentialsError): +class M365DefaultAzureCredentialError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6017, file=file, original_exception=original_exception, message=message ) -class Microsoft365InteractiveBrowserCredentialError(Microsoft365CredentialsError): +class M365InteractiveBrowserCredentialError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6018, file=file, original_exception=original_exception, message=message ) -class Microsoft365BrowserAuthNoTenantIDError(Microsoft365CredentialsError): +class M365BrowserAuthNoTenantIDError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6019, file=file, original_exception=original_exception, message=message ) -class Microsoft365BrowserAuthNoFlagError(Microsoft365CredentialsError): +class M365BrowserAuthNoFlagError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6020, file=file, original_exception=original_exception, message=message ) -class Microsoft365NotTenantIdButClientIdAndClientSecretError( - Microsoft365CredentialsError -): +class M365NotTenantIdButClientIdAndClientSecretError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6021, file=file, original_exception=original_exception, message=message ) + + +class M365MissingEnvironmentUserCredentialsError(M365CredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 6022, file=file, original_exception=original_exception, message=message + ) + + +class M365EnvironmentUserCredentialsError(M365CredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 6023, file=file, original_exception=original_exception, message=message + ) diff --git a/prowler/providers/microsoft365/lib/arguments/__init__.py b/prowler/providers/m365/lib/__init__.py similarity index 100% rename from prowler/providers/microsoft365/lib/arguments/__init__.py rename to prowler/providers/m365/lib/__init__.py diff --git a/prowler/providers/microsoft365/lib/mutelist/__init__.py b/prowler/providers/m365/lib/arguments/__init__.py similarity index 100% rename from prowler/providers/microsoft365/lib/mutelist/__init__.py rename to prowler/providers/m365/lib/arguments/__init__.py diff --git a/prowler/providers/m365/lib/arguments/arguments.py b/prowler/providers/m365/lib/arguments/arguments.py new file mode 100644 index 0000000000..a1980c4bd9 --- /dev/null +++ b/prowler/providers/m365/lib/arguments/arguments.py @@ -0,0 +1,61 @@ +def init_parser(self): + """Init the M365 Provider CLI parser""" + m365_parser = self.subparsers.add_parser( + "m365", + parents=[self.common_providers_parser], + help="M365 Provider", + ) + # Authentication Modes + m365_auth_subparser = m365_parser.add_argument_group("Authentication Modes") + m365_auth_modes_group = m365_auth_subparser.add_mutually_exclusive_group() + m365_auth_modes_group.add_argument( + "--az-cli-auth", + action="store_true", + help="Use Azure CLI authentication to log in against Microsoft 365", + ) + m365_auth_modes_group.add_argument( + "--env-auth", + action="store_true", + help="Use User and Password environment variables authentication to log in against Microsoft 365", + ) + m365_auth_modes_group.add_argument( + "--sp-env-auth", + action="store_true", + help="Use Azure Service Principal environment variables authentication to log in against Microsoft 365", + ) + m365_auth_modes_group.add_argument( + "--browser-auth", + action="store_true", + help="Use Azure interactive browser authentication to log in against Microsoft 365", + ) + m365_parser.add_argument( + "--tenant-id", + nargs="?", + default=None, + help="Microsoft 365 Tenant ID to be used with --browser-auth option", + ) + m365_parser.add_argument( + "--user", + nargs="?", + default=None, + help="Microsoft 365 user email", + ) + m365_parser.add_argument( + "--encypted-password", + nargs="?", + default=None, + help="Microsoft 365 encrypted password", + ) + # Regions + m365_regions_subparser = m365_parser.add_argument_group("Regions") + m365_regions_subparser.add_argument( + "--region", + nargs="?", + default="M365Global", + choices=[ + "M365Global", + "M365GlobalChina", + "M365USGovernment", + ], + help="Microsoft 365 region to be used, default is M365Global", + ) diff --git a/prowler/providers/microsoft365/lib/regions/__init__.py b/prowler/providers/m365/lib/mutelist/__init__.py similarity index 100% rename from prowler/providers/microsoft365/lib/regions/__init__.py rename to prowler/providers/m365/lib/mutelist/__init__.py diff --git a/prowler/providers/microsoft365/lib/mutelist/mutelist.py b/prowler/providers/m365/lib/mutelist/mutelist.py similarity index 74% rename from prowler/providers/microsoft365/lib/mutelist/mutelist.py rename to prowler/providers/m365/lib/mutelist/mutelist.py index 21669d9d04..a7bf971f3e 100644 --- a/prowler/providers/microsoft365/lib/mutelist/mutelist.py +++ b/prowler/providers/m365/lib/mutelist/mutelist.py @@ -1,12 +1,12 @@ -from prowler.lib.check.models import CheckReportMicrosoft365 +from prowler.lib.check.models import CheckReportM365 from prowler.lib.mutelist.mutelist import Mutelist from prowler.lib.outputs.utils import unroll_dict, unroll_tags -class Microsoft365Mutelist(Mutelist): +class M365Mutelist(Mutelist): def is_finding_muted( self, - finding: CheckReportMicrosoft365, + finding: CheckReportM365, ) -> bool: return self.is_muted( finding.tenant_id, diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py new file mode 100644 index 0000000000..367b1fe2af --- /dev/null +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -0,0 +1,171 @@ +import msal + +from prowler.lib.powershell.powershell import PowerShellSession +from prowler.providers.m365.models import M365Credentials + + +class M365PowerShell(PowerShellSession): + """ + Microsoft 365 specific PowerShell session management implementation. + + This class extends the base PowerShellSession to provide Microsoft 365 specific + functionality, including authentication, Teams management, and Exchange Online + operations. + + Features: + - Microsoft 365 credential management + - Teams client configuration + - Exchange Online connectivity + - Audit log configuration + - Secure credential handling + + Attributes: + credentials (M365Credentials): The Microsoft 365 credentials used for authentication. + + Note: + This class requires the Microsoft Teams and Exchange Online PowerShell modules + to be installed and available in the PowerShell environment. + """ + + def __init__(self, credentials: M365Credentials): + """ + Initialize a Microsoft 365 PowerShell session. + + Sets up the PowerShell session and initializes the provided credentials + for Microsoft 365 authentication. + + Args: + credentials (M365Credentials): The Microsoft 365 credentials to use + for authentication. + """ + super().__init__() + self.init_credential(credentials) + + def init_credential(self, credentials: M365Credentials) -> None: + """ + Initialize PowerShell credential object for Microsoft 365 authentication. + + Sanitizes the username and password, then creates a PSCredential object + in the PowerShell session for use with Microsoft 365 cmdlets. + + Args: + credentials (M365Credentials): The credentials object containing + username and password. + + Note: + The credentials are sanitized to prevent command injection and + stored securely in the PowerShell session. + """ + # Sanitize user and password + user = self.sanitize(credentials.user) + passwd = self.sanitize(credentials.passwd) + + # Securely convert encrypted password to SecureString + self.execute(f'$user = "{user}"') + self.execute(f'$secureString = "{passwd}" | ConvertTo-SecureString') + self.execute( + "$credential = New-Object System.Management.Automation.PSCredential ($user, $secureString)" + ) + + def test_credentials(self, credentials: M365Credentials) -> bool: + """ + Test Microsoft 365 credentials by attempting to authenticate against Entra ID. + + Args: + credentials (M365Credentials): The credentials object containing + username and password to test. + + Returns: + bool: True if credentials are valid and authentication succeeds, False otherwise. + """ + self.execute( + f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString\n' + ) + self.execute( + f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' + ) + self.process.stdin.write( + 'Write-Output "$($credential.GetNetworkCredential().Password)"\n' + ) + self.process.stdin.write(f"Write-Output '{self.END}'\n") + decrypted_password = self.read_output() + + app = msal.ConfidentialClientApplication( + client_id=credentials.client_id, + client_credential=credentials.client_secret, + authority=f"https://login.microsoftonline.com/{credentials.tenant_id}", + ) + + result = app.acquire_token_by_username_password( + username=credentials.user, + password=decrypted_password, # Needs to be in plain text + scopes=["https://graph.microsoft.com/.default"], + ) + + return "access_token" in result + + def connect_microsoft_teams(self) -> dict: + """ + Connect to Microsoft Teams Module PowerShell Module. + + Establishes a connection to Microsoft Teams using the initialized credentials. + + Returns: + dict: Connection status information in JSON format. + + Note: + This method requires the Microsoft Teams PowerShell module to be installed. + """ + return self.execute("Connect-MicrosoftTeams -Credential $credential") + + def get_teams_settings(self) -> dict: + """ + Get Teams Client Settings. + + Retrieves the current Microsoft Teams client configuration settings. + + Returns: + dict: Teams client configuration settings in JSON format. + + Example: + >>> get_teams_settings() + { + "AllowBox": true, + "AllowDropBox": true, + "AllowGoogleDrive": true + } + """ + return self.execute("Get-CsTeamsClientConfiguration | ConvertTo-Json") + + def connect_exchange_online(self) -> dict: + """ + Connect to Exchange Online PowerShell Module. + + Establishes a connection to Exchange Online using the initialized credentials. + + Returns: + dict: Connection status information in JSON format. + + Note: + This method requires the Exchange Online PowerShell module to be installed. + """ + return self.execute("Connect-ExchangeOnline -Credential $credential") + + def get_audit_log_config(self) -> dict: + """ + Get Purview Admin Audit Log Settings. + + Retrieves the current audit log configuration settings for Microsoft Purview. + + Returns: + dict: Audit log configuration settings in JSON format. + + Example: + >>> get_audit_log_config() + { + "UnifiedAuditLogIngestionEnabled": true + } + """ + return self.execute( + "Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json" + ) diff --git a/prowler/providers/microsoft365/lib/service/__init__.py b/prowler/providers/m365/lib/regions/__init__.py similarity index 100% rename from prowler/providers/microsoft365/lib/service/__init__.py rename to prowler/providers/m365/lib/regions/__init__.py diff --git a/prowler/providers/microsoft365/lib/regions/regions.py b/prowler/providers/m365/lib/regions/regions.py similarity index 90% rename from prowler/providers/microsoft365/lib/regions/regions.py rename to prowler/providers/m365/lib/regions/regions.py index b9e6d1969a..1f3fd8cfbf 100644 --- a/prowler/providers/microsoft365/lib/regions/regions.py +++ b/prowler/providers/m365/lib/regions/regions.py @@ -8,17 +8,17 @@ MICROSOFT365_GENERIC_CLOUD = "https://graph.microsoft.com" def get_regions_config(region): allowed_regions = { - "Microsoft365Global": { + "M365Global": { "authority": None, "base_url": MICROSOFT365_GENERIC_CLOUD, "credential_scopes": [MICROSOFT365_GENERIC_CLOUD + "/.default"], }, - "Microsoft365China": { + "M365China": { "authority": AzureAuthorityHosts.AZURE_CHINA, "base_url": MICROSOFT365_CHINA_CLOUD, "credential_scopes": [MICROSOFT365_CHINA_CLOUD + "/.default"], }, - "Microsoft365USGovernment": { + "M365USGovernment": { "authority": AzureAuthorityHosts.AZURE_GOVERNMENT, "base_url": MICROSOFT365_US_GOV_CLOUD, "credential_scopes": [MICROSOFT365_US_GOV_CLOUD + "/.default"], diff --git a/prowler/providers/microsoft365/services/admincenter/__init__.py b/prowler/providers/m365/lib/service/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/admincenter/__init__.py rename to prowler/providers/m365/lib/service/__init__.py diff --git a/prowler/providers/m365/lib/service/service.py b/prowler/providers/m365/lib/service/service.py new file mode 100644 index 0000000000..02aeb2762c --- /dev/null +++ b/prowler/providers/m365/lib/service/service.py @@ -0,0 +1,17 @@ +from msgraph import GraphServiceClient + +from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell +from prowler.providers.m365.m365_provider import M365Provider + + +class M365Service: + def __init__( + self, + provider: M365Provider, + ): + self.client = GraphServiceClient(credentials=provider.session) + self.audit_config = provider.audit_config + self.fixer_config = provider.fixer_config + + if provider.credentials: + self.powershell = M365PowerShell(provider.credentials) diff --git a/prowler/providers/microsoft365/microsoft365_provider.py b/prowler/providers/m365/m365_provider.py similarity index 57% rename from prowler/providers/microsoft365/microsoft365_provider.py rename to prowler/providers/m365/m365_provider.py index 668381d576..cd4438da72 100644 --- a/prowler/providers/microsoft365/microsoft365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -25,88 +25,96 @@ from prowler.lib.logger import logger from prowler.lib.utils.utils import print_boxes from prowler.providers.common.models import Audit_Metadata, Connection from prowler.providers.common.provider import Provider -from prowler.providers.microsoft365.exceptions.exceptions import ( - Microsoft365ArgumentTypeValidationError, - Microsoft365BrowserAuthNoFlagError, - Microsoft365BrowserAuthNoTenantIDError, - Microsoft365ClientAuthenticationError, - Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError, - Microsoft365ConfigCredentialsError, - Microsoft365CredentialsUnavailableError, - Microsoft365DefaultAzureCredentialError, - Microsoft365EnvironmentVariableError, - Microsoft365GetTokenIdentityError, - Microsoft365HTTPResponseError, - Microsoft365InteractiveBrowserCredentialError, - Microsoft365InvalidProviderIdError, - Microsoft365NoAuthenticationMethodError, - Microsoft365NotTenantIdButClientIdAndClientSecretError, - Microsoft365NotValidClientIdError, - Microsoft365NotValidClientSecretError, - Microsoft365NotValidTenantIdError, - Microsoft365SetUpRegionConfigError, - Microsoft365SetUpSessionError, - Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError, - Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError, +from prowler.providers.m365.exceptions.exceptions import ( + M365ArgumentTypeValidationError, + M365BrowserAuthNoFlagError, + M365BrowserAuthNoTenantIDError, + M365ClientAuthenticationError, + M365ClientIdAndClientSecretNotBelongingToTenantIdError, + M365ConfigCredentialsError, + M365CredentialsUnavailableError, + M365DefaultAzureCredentialError, + M365EnvironmentUserCredentialsError, + M365EnvironmentVariableError, + M365GetTokenIdentityError, + M365HTTPResponseError, + M365InteractiveBrowserCredentialError, + M365InvalidProviderIdError, + M365MissingEnvironmentUserCredentialsError, + M365NoAuthenticationMethodError, + M365NotTenantIdButClientIdAndClientSecretError, + M365NotValidClientIdError, + M365NotValidClientSecretError, + M365NotValidTenantIdError, + M365SetUpRegionConfigError, + M365SetUpSessionError, + M365TenantIdAndClientIdNotBelongingToClientSecretError, + M365TenantIdAndClientSecretNotBelongingToClientIdError, ) -from prowler.providers.microsoft365.lib.mutelist.mutelist import Microsoft365Mutelist -from prowler.providers.microsoft365.lib.regions.regions import get_regions_config -from prowler.providers.microsoft365.models import ( - Microsoft365IdentityInfo, - Microsoft365RegionConfig, +from prowler.providers.m365.lib.mutelist.mutelist import M365Mutelist +from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell +from prowler.providers.m365.lib.regions.regions import get_regions_config +from prowler.providers.m365.models import ( + M365Credentials, + M365IdentityInfo, + M365RegionConfig, ) -class Microsoft365Provider(Provider): +class M365Provider(Provider): """ - Represents an Microsoft365 provider. + Represents an M365 provider. - This class provides functionality to interact with the Microsoft365 resources. + This class provides functionality to interact with the M365 resources. It handles authentication, region configuration, and provides access to various properties and methods - related to the Microsoft365 provider. + related to the M365 provider. Attributes: - _type (str): The type of the provider, which is set to "microsoft365". - _session (DefaultMicrosoft365Credential): The session object associated with the Microsoft365 provider. - _identity (Microsoft365IdentityInfo): The identity information for the Microsoft365 provider. - _audit_config (dict): The audit configuration for the Microsoft365 provider. - _region_config (Microsoft365RegionConfig): The region configuration for the Microsoft365 provider. - _mutelist (Microsoft365Mutelist): The mutelist object associated with the Microsoft365 provider. - audit_metadata (Audit_Metadata): The audit metadata for the Microsoft365 provider. + _type (str): The type of the provider, which is set to "m365". + _session (DefaultM365Credential): The session object associated with the M365 provider. + _identity (M365IdentityInfo): The identity information for the M365 provider. + _audit_config (dict): The audit configuration for the M365 provider. + _region_config (M365RegionConfig): The region configuration for the M365 provider. + _mutelist (M365Mutelist): The mutelist object associated with the M365 provider. + audit_metadata (Audit_Metadata): The audit metadata for the M365 provider. Methods: - __init__ -> Initializes the Microsoft365 provider. - identity(self): Returns the identity of the Microsoft365 provider. - type(self): Returns the type of the Microsoft365 provider. - session(self): Returns the session object associated with the Microsoft365 provider. - region_config(self): Returns the region configuration for the Microsoft365 provider. - audit_config(self): Returns the audit configuration for the Microsoft365 provider. + __init__ -> Initializes the M365 provider. + identity(self): Returns the identity of the M365 provider. + type(self): Returns the type of the M365 provider. + session(self): Returns the session object associated with the M365 provider. + region_config(self): Returns the region configuration for the M365 provider. + audit_config(self): Returns the audit configuration for the M365 provider. fixer_config(self): Returns the fixer configuration. - output_options(self, options: tuple): Sets the output options for the Microsoft365 provider. - mutelist(self) -> Microsoft365Mutelist: Returns the mutelist object associated with the Microsoft365 provider. - setup_region_config(cls, region): Sets up the region configuration for the Microsoft365 provider. - print_credentials(self): Prints the Microsoft365 credentials information. - setup_session(cls, az_cli_auth, app_env_auth, browser_auth, managed_identity_auth, tenant_id, region_config): Set up the Microsoft365 session with the specified authentication method. + output_options(self, options: tuple): Sets the output options for the M365 provider. + mutelist(self) -> M365Mutelist: Returns the mutelist object associated with the M365 provider. + setup_region_config(cls, region): Sets up the region configuration for the M365 provider. + print_credentials(self): Prints the M365 credentials information. + setup_session(cls, az_cli_auth, app_env_auth, browser_auth, managed_identity_auth, tenant_id, region_config): Set up the M365 session with the specified authentication method. """ - _type: str = "microsoft365" + _type: str = "m365" _session: DefaultAzureCredential # Must be used besides being named for Azure - _identity: Microsoft365IdentityInfo + _identity: M365IdentityInfo _audit_config: dict - _region_config: Microsoft365RegionConfig - _mutelist: Microsoft365Mutelist + _region_config: M365RegionConfig + _mutelist: M365Mutelist + _credentials: M365Credentials # TODO: this is not optional, enforce for all providers audit_metadata: Audit_Metadata def __init__( self, sp_env_auth: bool, + env_auth: bool, az_cli_auth: bool, browser_auth: bool, tenant_id: str = None, client_id: str = None, client_secret: str = None, - region: str = "Microsoft365Global", + user: str = None, + encrypted_password: str = None, + region: str = "M365Global", config_content: dict = None, config_path: str = None, mutelist_path: str = None, @@ -114,13 +122,13 @@ class Microsoft365Provider(Provider): fixer_config: dict = {}, ): """ - Initializes the Microsoft365 provider. + Initializes the M365 provider. Args: - tenant_id (str): The Microsoft365 Active Directory tenant ID. - region (str): The Microsoft365 region. - client_id (str): The Microsoft365 client ID. - client_secret (str): The Microsoft365 client secret. + tenant_id (str): The M365 Active Directory tenant ID. + region (str): The M365 region. + client_id (str): The M365 client ID. + client_secret (str): The M365 client secret. config_path (str): The path to the configuration file. config_content (dict): The configuration content. fixer_config (dict): The fixer configuration. @@ -131,13 +139,13 @@ class Microsoft365Provider(Provider): None Raises: - Microsoft365ArgumentTypeValidationError: If there is an error in the argument type validation. - Microsoft365SetUpRegionConfigError: If there is an error in setting up the region configuration. - Microsoft365ConfigCredentialsError: If there is an error in configuring the Microsoft365 credentials from a dictionary. - Microsoft365GetTokenIdentityError: If there is an error in getting the token from the Microsoft365 identity. - Microsoft365HTTPResponseError: If there is an HTTP response error. + M365ArgumentTypeValidationError: If there is an error in the argument type validation. + M365SetUpRegionConfigError: If there is an error in setting up the region configuration. + M365ConfigCredentialsError: If there is an error in configuring the M365 credentials from a dictionary. + M365GetTokenIdentityError: If there is an error in getting the token from the M365 identity. + M365HTTPResponseError: If there is an HTTP response error. """ - logger.info("Setting Microsoft365 provider ...") + logger.info("Setting M365 provider ...") logger.info("Checking if any credentials mode is set ...") @@ -145,36 +153,48 @@ class Microsoft365Provider(Provider): self.validate_arguments( az_cli_auth, sp_env_auth, + env_auth, browser_auth, tenant_id, client_id, client_secret, + user, + encrypted_password, ) logger.info("Checking if region is different than default one") self._region_config = self.setup_region_config(region) # Get the dict from the static credentials - microsoft365_credentials = None - if tenant_id and client_id and client_secret: - microsoft365_credentials = self.validate_static_credentials( - tenant_id=tenant_id, client_id=client_id, client_secret=client_secret + m365_credentials = None + if tenant_id and client_id and client_secret and user and encrypted_password: + m365_credentials = self.validate_static_credentials( + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + user=user, + encrypted_password=encrypted_password, ) - # Set up the Microsoft365 session + # Set up the M365 session self._session = self.setup_session( az_cli_auth, sp_env_auth, + env_auth, browser_auth, tenant_id, - microsoft365_credentials, + m365_credentials, self._region_config, ) + # Set up PowerShell session credentials + self._credentials = self.setup_powershell(env_auth, m365_credentials) + # Set up the identity self._identity = self.setup_identity( az_cli_auth, sp_env_auth, + env_auth, browser_auth, client_id, ) @@ -192,13 +212,13 @@ class Microsoft365Provider(Provider): # Mutelist if mutelist_content: - self._mutelist = Microsoft365Mutelist( + self._mutelist = M365Mutelist( mutelist_content=mutelist_content, ) else: if not mutelist_path: mutelist_path = get_default_mute_file_path(self.type) - self._mutelist = Microsoft365Mutelist( + self._mutelist = M365Mutelist( mutelist_path=mutelist_path, ) @@ -206,27 +226,27 @@ class Microsoft365Provider(Provider): @property def identity(self): - """Returns the identity of the Microsoft365 provider.""" + """Returns the identity of the M365 provider.""" return self._identity @property def type(self): - """Returns the type of the Microsoft365 provider.""" + """Returns the type of the M365 provider.""" return self._type @property def session(self): - """Returns the session object associated with the Microsoft365 provider.""" + """Returns the session object associated with the M365 provider.""" return self._session @property def region_config(self): - """Returns the region configuration for the Microsoft365 provider.""" + """Returns the region configuration for the M365 provider.""" return self._region_config @property def audit_config(self): - """Returns the audit configuration for the Microsoft365 provider.""" + """Returns the audit configuration for the M365 provider.""" return self._audit_config @property @@ -235,73 +255,89 @@ class Microsoft365Provider(Provider): return self._fixer_config @property - def mutelist(self) -> Microsoft365Mutelist: - """Mutelist object associated with this Microsoft365 provider.""" + def mutelist(self) -> M365Mutelist: + """Mutelist object associated with this M365 provider.""" return self._mutelist + @property + def credentials(self) -> M365Credentials: + """Return powershell credentials""" + return self._credentials + @staticmethod def validate_arguments( az_cli_auth: bool, sp_env_auth: bool, + env_auth: bool, browser_auth: bool, tenant_id: str, client_id: str, client_secret: str, + user: str, + encrypted_password: str, ): """ - Validates the authentication arguments for the Microsoft365 provider. + Validates the authentication arguments for the M365 provider. Args: az_cli_auth (bool): Flag indicating whether Azure CLI authentication is enabled. sp_env_auth (bool): Flag indicating whether application authentication with environment variables is enabled. + env_auth: (bool): Flag indicating whether to use application and PowerShell authentication with environment variables. browser_auth (bool): Flag indicating whether browser authentication is enabled. - tenant_id (str): The Microsoft365 Tenant ID. - client_id (str): The Microsoft365 Client ID. - client_secret (str): The Microsoft365 Client Secret. + tenant_id (str): The M365 Tenant ID. + client_id (str): The M365 Client ID. + client_secret (str): The M365 Client Secret. + user (str): The M365 User Account. + encrpted_password (str): The M365 Encrypted Password. Raises: - Microsoft365BrowserAuthNoTenantIDError: If browser authentication is enabled but the tenant ID is not found. + M365BrowserAuthNoTenantIDError: If browser authentication is enabled but the tenant ID is not found. """ - if not client_id and not client_secret: + if not client_id and not client_secret and not user and not encrypted_password: if not browser_auth and tenant_id: - raise Microsoft365BrowserAuthNoFlagError( + raise M365BrowserAuthNoFlagError( file=os.path.basename(__file__), - message="Microsoft365 tenant ID error: browser authentication flag (--browser-auth) not found", + message="M365 tenant ID error: browser authentication flag (--browser-auth) not found", ) - elif not az_cli_auth and not sp_env_auth and not browser_auth: - raise Microsoft365NoAuthenticationMethodError( + elif ( + not az_cli_auth + and not sp_env_auth + and not browser_auth + and not env_auth + ): + raise M365NoAuthenticationMethodError( file=os.path.basename(__file__), - message="Microsoft365 provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth]", + message="M365 provider requires at least one authentication method set: [--env-auth | --az-cli-auth | --sp-env-auth | --browser-auth]", ) elif browser_auth and not tenant_id: - raise Microsoft365BrowserAuthNoTenantIDError( + raise M365BrowserAuthNoTenantIDError( file=os.path.basename(__file__), - message="Microsoft365 Tenant ID (--tenant-id) is required for browser authentication mode", + message="M365 Tenant ID (--tenant-id) is required for browser authentication mode", ) else: if not tenant_id: - raise Microsoft365NotTenantIdButClientIdAndClientSecretError( + raise M365NotTenantIdButClientIdAndClientSecretError( file=os.path.basename(__file__), - message="Tenant Id is required for Microsoft365 static credentials. Make sure you are using the correct credentials.", + message="Tenant Id is required for M365 static credentials. Make sure you are using the correct credentials.", ) @staticmethod def setup_region_config(region): """ - Sets up the region configuration for the Microsoft365 provider. + Sets up the region configuration for the M365 provider. Args: region (str): The name of the region. Returns: - Microsoft365RegionConfig: The region configuration object. + M365RegionConfig: The region configuration object. """ try: config = get_regions_config(region) - return Microsoft365RegionConfig( + return M365RegionConfig( name=region, authority=config["authority"], base_url=config["base_url"], @@ -311,7 +347,7 @@ class Microsoft365Provider(Provider): logger.error( f"{validation_error.__class__.__name__}[{validation_error.__traceback__.tb_lineno}]: {validation_error}" ) - raise Microsoft365ArgumentTypeValidationError( + raise M365ArgumentTypeValidationError( file=os.path.basename(__file__), original_exception=validation_error, ) @@ -319,16 +355,74 @@ class Microsoft365Provider(Provider): logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) - raise Microsoft365SetUpRegionConfigError( + raise M365SetUpRegionConfigError( file=os.path.basename(__file__), original_exception=error, ) - def print_credentials(self): - """Microsoft365 credentials information. + @staticmethod + def setup_powershell( + env_auth: bool = False, m365_credentials: dict = {} + ) -> M365Credentials: + """Gets the M365 credentials. - This method prints the Microsoft365 Tenant Domain, Microsoft365 Tenant ID, Microsoft365 Region, - Microsoft365 Subscriptions, Microsoft365 Identity Type, and Microsoft365 Identity ID. + Args: + env_auth: (bool): Flag indicating whether to use application and PowerShell authentication with environment variables. + + Returns: + M365Credentials: Object containing the user credentials. + If env_auth is True, retrieves from environment variables. + If False, returns empty credentials. + """ + credentials = None + if m365_credentials: + credentials = M365Credentials( + user=m365_credentials.get("user", ""), + passwd=m365_credentials.get("encrypted_password", ""), + client_id=m365_credentials.get("client_id", ""), + client_secret=m365_credentials.get("client_secret", ""), + tenant_id=m365_credentials.get("tenant_id", ""), + ) + elif env_auth: + m365_user = getenv("M365_USER") + m365_password = getenv("M365_ENCRYPTED_PASSWORD") + client_id = getenv("AZURE_CLIENT_ID") + client_secret = getenv("AZURE_CLIENT_SECRET") + tenant_id = getenv("AZURE_TENANT_ID") + + if not m365_user or not m365_password: + logger.critical( + "M365 provider: Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables needed for credentials authentication" + ) + raise M365MissingEnvironmentUserCredentialsError( + file=os.path.basename(__file__), + message="Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication.", + ) + credentials = M365Credentials( + user=m365_user, + passwd=m365_password, + client_id=client_id, + client_secret=client_secret, + tenant_id=tenant_id, + ) + + if credentials: + test_session = M365PowerShell(credentials) + try: + if test_session.test_credentials(credentials): + return credentials + raise M365EnvironmentUserCredentialsError( + file=os.path.basename(__file__), + message="M365_USER or M365_ENCRYPTED_PASSWORD environment variables are not correct. Please ensure you are using the right credentials.", + ) + finally: + test_session.close() + + def print_credentials(self): + """M365 credentials information. + + This method prints the M365 Tenant Domain, M365 Tenant ID, M365 Region, + M365 Subscriptions, M365 Identity Type, and M365 Identity ID. Args: None @@ -337,12 +431,13 @@ class Microsoft365Provider(Provider): None """ report_lines = [ - f"Microsoft365 Region: {Fore.YELLOW}{self.region_config.name}{Style.RESET_ALL}", - f"Microsoft365 Tenant Domain: {Fore.YELLOW}{self._identity.tenant_domain}{Style.RESET_ALL} Microsoft365 Tenant ID: {Fore.YELLOW}{self._identity.tenant_id}{Style.RESET_ALL}", - f"Microsoft365 Identity Type: {Fore.YELLOW}{self._identity.identity_type}{Style.RESET_ALL} Microsoft365 Identity ID: {Fore.YELLOW}{self._identity.identity_id}{Style.RESET_ALL}", + f"M365 Region: {Fore.YELLOW}{self.region_config.name}{Style.RESET_ALL}", + f"M365 Tenant Domain: {Fore.YELLOW}{self._identity.tenant_domain}{Style.RESET_ALL} M365 Tenant ID: {Fore.YELLOW}{self._identity.tenant_id}{Style.RESET_ALL}", + f"M365 Identity Type: {Fore.YELLOW}{self._identity.identity_type}{Style.RESET_ALL} M365 Identity ID: {Fore.YELLOW}{self._identity.identity_id}{Style.RESET_ALL}", + f"M365 User: {Fore.YELLOW}{self.credentials.user}{Style.RESET_ALL}", ] report_title = ( - f"{Style.BRIGHT}Using the Microsoft365 credentials below:{Style.RESET_ALL}" + f"{Style.BRIGHT}Using the M365 credentials below:{Style.RESET_ALL}" ) print_boxes(report_lines, report_title) @@ -352,72 +447,71 @@ class Microsoft365Provider(Provider): def setup_session( az_cli_auth: bool, sp_env_auth: bool, + env_auth: bool, browser_auth: bool, tenant_id: str, - microsoft365_credentials: dict, - region_config: Microsoft365RegionConfig, + m365_credentials: dict, + region_config: M365RegionConfig, ): - """Returns the Microsoft365 credentials object. + """Returns the M365 credentials object. - Set up the Microsoft365 session with the specified authentication method. + Set up the M365 session with the specified authentication method. Args: az_cli_auth (bool): Flag indicating whether to use Azure CLI authentication. sp_env_auth (bool): Flag indicating whether to use application authentication with environment variables. browser_auth (bool): Flag indicating whether to use interactive browser authentication. - tenant_id (str): The Microsoft365 Active Directory tenant ID. - microsoft365_credentials (dict): The Microsoft365 configuration object. It contains the following keys: - - tenant_id: The Microsoft365 Active Directory tenant ID. - - client_id: The Microsoft365 client ID. - - client_secret: The Microsoft365 client secret - region_config (Microsoft365RegionConfig): The region configuration object. + tenant_id (str): The M365 Active Directory tenant ID. + m365_credentials (dict): The M365 configuration object. It contains the following keys: + - tenant_id: The M365 Active Directory tenant ID. + - client_id: The M365 client ID. + - client_secret: The M365 client secret + region_config (M365RegionConfig): The region configuration object. Returns: - credentials: The Microsoft365 credentials object. + credentials: The M365 credentials object. Raises: - Exception: If failed to retrieve Microsoft365 credentials. + Exception: If failed to retrieve M365 credentials. """ if not browser_auth: - if sp_env_auth: + if sp_env_auth or env_auth: try: - Microsoft365Provider.check_service_principal_creds_env_vars() - except ( - Microsoft365EnvironmentVariableError - ) as environment_credentials_error: + M365Provider.check_service_principal_creds_env_vars() + except M365EnvironmentVariableError as environment_credentials_error: logger.critical( f"{environment_credentials_error.__class__.__name__}[{environment_credentials_error.__traceback__.tb_lineno}] -- {environment_credentials_error}" ) raise environment_credentials_error try: - if microsoft365_credentials: + if m365_credentials: try: credentials = ClientSecretCredential( - tenant_id=microsoft365_credentials["tenant_id"], - client_id=microsoft365_credentials["client_id"], - client_secret=microsoft365_credentials["client_secret"], + tenant_id=m365_credentials["tenant_id"], + client_id=m365_credentials["client_id"], + client_secret=m365_credentials["client_secret"], ) return credentials except ClientAuthenticationError as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365ClientAuthenticationError( + raise M365ClientAuthenticationError( file=os.path.basename(__file__), original_exception=error ) except CredentialUnavailableError as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365CredentialsUnavailableError( + raise M365CredentialsUnavailableError( file=os.path.basename(__file__), original_exception=error ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365ConfigCredentialsError( + raise M365ConfigCredentialsError( file=os.path.basename(__file__), original_exception=error ) else: @@ -425,15 +519,17 @@ class Microsoft365Provider(Provider): # DefaultAzureCredential sets just one authentication method, excluding the others try: credentials = DefaultAzureCredential( - exclude_environment_credential=not sp_env_auth, + exclude_environment_credential=not ( + sp_env_auth or env_auth + ), exclude_cli_credential=not az_cli_auth, - # Microsoft365 Auth using Managed Identity is not supported + # M365 Auth using Managed Identity is not supported exclude_managed_identity_credential=True, - # Microsoft365 Auth using Visual Studio is not supported + # M365 Auth using Visual Studio is not supported exclude_visual_studio_code_credential=True, - # Microsoft365 Auth using Shared Token Cache is not supported + # M365 Auth using Shared Token Cache is not supported exclude_shared_token_cache_credential=True, - # Microsoft365 Auth using PowerShell is not supported + # M365 Auth using PowerShell is not supported exclude_powershell_credential=True, # set Authority of a Microsoft Entra endpoint authority=region_config.authority, @@ -442,29 +538,29 @@ class Microsoft365Provider(Provider): logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365ClientAuthenticationError( + raise M365ClientAuthenticationError( file=os.path.basename(__file__), original_exception=error ) except CredentialUnavailableError as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365CredentialsUnavailableError( + raise M365CredentialsUnavailableError( file=os.path.basename(__file__), original_exception=error ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365DefaultAzureCredentialError( + raise M365DefaultAzureCredentialError( file=os.path.basename(__file__), original_exception=error ) except Exception as error: - logger.critical("Failed to retrieve Microsoft365 credentials") + logger.critical("Failed to retrieve M365 credentials") logger.critical( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365SetUpSessionError( + raise M365SetUpSessionError( file=os.path.basename(__file__), original_exception=error ) else: @@ -472,12 +568,12 @@ class Microsoft365Provider(Provider): credentials = InteractiveBrowserCredential(tenant_id=tenant_id) except Exception as error: logger.critical( - "Failed to retrieve Microsoft365 credentials using browser authentication" + "Failed to retrieve M365 credentials using browser authentication" ) logger.critical( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365InteractiveBrowserCredentialError( + raise M365InteractiveBrowserCredentialError( file=os.path.basename(__file__), original_exception=error ) @@ -487,95 +583,104 @@ class Microsoft365Provider(Provider): def test_connection( az_cli_auth: bool = False, sp_env_auth: bool = False, + env_auth: bool = False, browser_auth: bool = False, tenant_id: str = None, - region: str = "Microsoft365Global", + region: str = "M365Global", raise_on_exception=True, client_id=None, client_secret=None, + user=None, + encrypted_password=None, ) -> Connection: - """Test connection to Microsoft365 subscription. + """Test connection to M365 subscription. - Test the connection to an Microsoft365 subscription using the provided credentials. + Test the connection to an M365 subscription using the provided credentials. Args: az_cli_auth (bool): Flag indicating whether to use Azure CLI authentication. sp_env_auth (bool): Flag indicating whether to use application authentication with environment variables. + env_auth: (bool): Flag indicating whether to use application and PowerShell authentication with environment variables. browser_auth (bool): Flag indicating whether to use interactive browser authentication. - tenant_id (str): The Microsoft365 Active Directory tenant ID. - region (str): The Microsoft365 region. + tenant_id (str): The M365 Active Directory tenant ID. + region (str): The M365 region. raise_on_exception (bool): Flag indicating whether to raise an exception if the connection fails. - client_id (str): The Microsoft365 client ID. - client_secret (str): The Microsoft365 client secret. + client_id (str): The M365 client ID. + client_secret (str): The M365 client secret. + user (str): The M365 user email. + encrypted_password (str): The M365 encrypted_password. + Returns: bool: True if the connection is successful, False otherwise. Raises: - Exception: If failed to test the connection to Microsoft365 subscription. - Microsoft365ArgumentTypeValidationError: If there is an error in the argument type validation. - Microsoft365SetUpRegionConfigError: If there is an error in setting up the region configuration. - Microsoft365InteractiveBrowserCredentialError: If there is an error in retrieving the Microsoft365 credentials using browser authentication. - Microsoft365HTTPResponseError: If there is an HTTP response error. - Microsoft365ConfigCredentialsError: If there is an error in configuring the Microsoft365 credentials from a dictionary. + Exception: If failed to test the connection to M365 subscription. + M365ArgumentTypeValidationError: If there is an error in the argument type validation. + M365SetUpRegionConfigError: If there is an error in setting up the region configuration. + M365InteractiveBrowserCredentialError: If there is an error in retrieving the M365 credentials using browser authentication. + M365HTTPResponseError: If there is an HTTP response error. + M365ConfigCredentialsError: If there is an error in configuring the M365 credentials from a dictionary. Examples: - >>> Microsoft365Provider.test_connection(az_cli_auth=True) + >>> M365Provider.test_connection(az_cli_auth=True) True - >>> Microsoft365Provider.test_connection(sp_env_auth=False, browser_auth=True, tenant_id=None) - False, ArgumentTypeError: Microsoft365 Tenant ID is required only for browser authentication mode - >>> Microsoft365Provider.test_connection(tenant_id="XXXXXXXXXX", client_id="XXXXXXXXXX", client_secret="XXXXXXXXXX") + >>> M365Provider.test_connection(sp_env_auth=False, browser_auth=True, tenant_id=None) + False, ArgumentTypeError: M365 Tenant ID is required only for browser authentication mode + >>> M365Provider.test_connection(tenant_id="XXXXXXXXXX", client_id="XXXXXXXXXX", client_secret="XXXXXXXXXX") True """ try: - Microsoft365Provider.validate_arguments( + M365Provider.validate_arguments( az_cli_auth, sp_env_auth, + env_auth, browser_auth, tenant_id, client_id, client_secret, + user, + encrypted_password, ) - region_config = Microsoft365Provider.setup_region_config(region) + region_config = M365Provider.setup_region_config(region) # Get the dict from the static credentials - microsoft365_credentials = None + m365_credentials = None if tenant_id and client_id and client_secret: - microsoft365_credentials = ( - Microsoft365Provider.validate_static_credentials( - tenant_id=tenant_id, - client_id=client_id, - client_secret=client_secret, - ) + m365_credentials = M365Provider.validate_static_credentials( + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, ) - # Set up the Microsoft365 session - credentials = Microsoft365Provider.setup_session( + # Set up the M365 session + credentials = M365Provider.setup_session( az_cli_auth, sp_env_auth, + env_auth, browser_auth, tenant_id, - microsoft365_credentials, + m365_credentials, region_config, ) GraphServiceClient(credentials=credentials) - logger.info("Microsoft365 provider: Connection to Microsoft365 successful") + logger.info("M365 provider: Connection to M365 successful") return Connection(is_connected=True) # Exceptions from setup_region_config - except Microsoft365ArgumentTypeValidationError as type_validation_error: + except M365ArgumentTypeValidationError as type_validation_error: logger.error( f"{type_validation_error.__class__.__name__}[{type_validation_error.__traceback__.tb_lineno}]: {type_validation_error}" ) if raise_on_exception: raise type_validation_error return Connection(error=type_validation_error) - except Microsoft365SetUpRegionConfigError as region_config_error: + except M365SetUpRegionConfigError as region_config_error: logger.error( f"{region_config_error.__class__.__name__}[{region_config_error.__traceback__.tb_lineno}]: {region_config_error}" ) @@ -583,28 +688,28 @@ class Microsoft365Provider(Provider): raise region_config_error return Connection(error=region_config_error) # Exceptions from setup_session - except Microsoft365EnvironmentVariableError as environment_credentials_error: + except M365EnvironmentVariableError as environment_credentials_error: logger.error( f"{environment_credentials_error.__class__.__name__}[{environment_credentials_error.__traceback__.tb_lineno}]: {environment_credentials_error}" ) if raise_on_exception: raise environment_credentials_error return Connection(error=environment_credentials_error) - except Microsoft365ConfigCredentialsError as config_credentials_error: + except M365ConfigCredentialsError as config_credentials_error: logger.error( f"{config_credentials_error.__class__.__name__}[{config_credentials_error.__traceback__.tb_lineno}]: {config_credentials_error}" ) if raise_on_exception: raise config_credentials_error return Connection(error=config_credentials_error) - except Microsoft365ClientAuthenticationError as client_auth_error: + except M365ClientAuthenticationError as client_auth_error: logger.error( f"{client_auth_error.__class__.__name__}[{client_auth_error.__traceback__.tb_lineno}]: {client_auth_error}" ) if raise_on_exception: raise client_auth_error return Connection(error=client_auth_error) - except Microsoft365CredentialsUnavailableError as credential_unavailable_error: + except M365CredentialsUnavailableError as credential_unavailable_error: logger.error( f"{credential_unavailable_error.__class__.__name__}[{credential_unavailable_error.__traceback__.tb_lineno}]: {credential_unavailable_error}" ) @@ -612,7 +717,7 @@ class Microsoft365Provider(Provider): raise credential_unavailable_error return Connection(error=credential_unavailable_error) except ( - Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError + M365ClientIdAndClientSecretNotBelongingToTenantIdError ) as tenant_id_error: logger.error( f"{tenant_id_error.__class__.__name__}[{tenant_id_error.__traceback__.tb_lineno}]: {tenant_id_error}" @@ -621,7 +726,7 @@ class Microsoft365Provider(Provider): raise tenant_id_error return Connection(error=tenant_id_error) except ( - Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError + M365TenantIdAndClientSecretNotBelongingToClientIdError ) as client_id_error: logger.error( f"{client_id_error.__class__.__name__}[{client_id_error.__traceback__.tb_lineno}]: {client_id_error}" @@ -630,7 +735,7 @@ class Microsoft365Provider(Provider): raise client_id_error return Connection(error=client_id_error) except ( - Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError + M365TenantIdAndClientIdNotBelongingToClientSecretError ) as client_secret_error: logger.error( f"{client_secret_error.__class__.__name__}[{client_secret_error.__traceback__.tb_lineno}]: {client_secret_error}" @@ -639,7 +744,7 @@ class Microsoft365Provider(Provider): raise client_secret_error return Connection(error=client_secret_error) # Exceptions from provider_id validation - except Microsoft365InvalidProviderIdError as invalid_credentials_error: + except M365InvalidProviderIdError as invalid_credentials_error: logger.error( f"{invalid_credentials_error.__class__.__name__}[{invalid_credentials_error.__traceback__.tb_lineno}]: {invalid_credentials_error}" ) @@ -652,7 +757,7 @@ class Microsoft365Provider(Provider): f"{http_response_error.__class__.__name__}[{http_response_error.__traceback__.tb_lineno}]: {http_response_error}" ) if raise_on_exception: - raise Microsoft365HTTPResponseError( + raise M365HTTPResponseError( file=os.path.basename(__file__), original_exception=http_response_error, ) @@ -679,14 +784,14 @@ class Microsoft365Provider(Provider): If any of the environment variables is missing, it logs a critical error and exits the program. """ logger.info( - "Microsoft365 provider: checking service principal environment variables ..." + "M365 provider: checking service principal environment variables ..." ) for env_var in ["AZURE_CLIENT_ID", "AZURE_TENANT_ID", "AZURE_CLIENT_SECRET"]: if not getenv(env_var): logger.critical( - f"Microsoft365 provider: Missing environment variable {env_var} needed to authenticate against Microsoft365" + f"M365 provider: Missing environment variable {env_var} needed to authenticate against M365." ) - raise Microsoft365EnvironmentVariableError( + raise M365EnvironmentVariableError( file=os.path.basename(__file__), message=f"Missing environment variable {env_var} required to authenticate.", ) @@ -695,32 +800,34 @@ class Microsoft365Provider(Provider): self, az_cli_auth, sp_env_auth, + env_auth, browser_auth, client_id, ): """ - Sets up the identity for the Microsoft365 provider. + Sets up the identity for the M365 provider. Args: az_cli_auth (bool): Flag indicating if Azure CLI authentication is used. sp_env_auth (bool): Flag indicating if application authentication with environment variables is used. + env_auth: (bool): Flag indicating whether to use application and PowerShell authentication with environment variables. browser_auth (bool): Flag indicating if interactive browser authentication is used. - client_id (str): The Microsoft365 client ID. + client_id (str): The M365 client ID. Returns: - Microsoft365IdentityInfo: An instance of Microsoft365IdentityInfo containing the identity information. + M365IdentityInfo: An instance of M365IdentityInfo containing the identity information. """ credentials = self.session # TODO: fill this object with real values not default and set to none - identity = Microsoft365IdentityInfo() + identity = M365IdentityInfo() # If credentials comes from service principal or browser, if the required permissions are assigned # the identity can access AAD and retrieve the tenant domain name. - # With cli also should be possible but right now it does not work, microsoft365 python package issue is coming + # With cli also should be possible but right now it does not work, m365 python package issue is coming # At the time of writting this with az cli creds is not working, despite that is included - if az_cli_auth or sp_env_auth or browser_auth or client_id: + if env_auth or az_cli_auth or sp_env_auth or browser_auth or client_id: - async def get_microsoft365_identity(): + async def get_m365_identity(): # Trying to recover tenant domain info try: logger.info( @@ -737,7 +844,7 @@ class Microsoft365Provider(Provider): logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365HTTPResponseError( + raise M365HTTPResponseError( file=os.path.basename(__file__), original_exception=error, ) @@ -745,7 +852,7 @@ class Microsoft365Provider(Provider): logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) - raise Microsoft365GetTokenIdentityError( + raise M365GetTokenIdentityError( file=os.path.basename(__file__), original_exception=error, ) @@ -754,7 +861,7 @@ class Microsoft365Provider(Provider): f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" ) # since that exception is not considered as critical, we keep filling another identity fields - if sp_env_auth or client_id: + if sp_env_auth or env_auth or client_id: # The id of the sp can be retrieved from environment variables identity.identity_id = getenv("AZURE_CLIENT_ID") identity.identity_type = "Service Principal" @@ -784,7 +891,7 @@ class Microsoft365Provider(Provider): organization_info = await client.organization.get() identity.tenant_id = organization_info.value[0].id - asyncio.get_event_loop().run_until_complete(get_microsoft365_identity()) + asyncio.get_event_loop().run_until_complete(get_m365_identity()) return identity @staticmethod @@ -792,20 +899,20 @@ class Microsoft365Provider(Provider): tenant_id: str = None, client_id: str = None, client_secret: str = None ) -> dict: """ - Validates the static credentials for the Microsoft365 provider. + Validates the static credentials for the M365 provider. Args: - tenant_id (str): The Microsoft365 Active Directory tenant ID. - client_id (str): The Microsoft365 client ID. - client_secret (str): The Microsoft365 client secret. + tenant_id (str): The M365 Active Directory tenant ID. + client_id (str): The M365 client ID. + client_secret (str): The M365 client secret. Raises: - Microsoft365NotValidTenantIdError: If the provided Microsoft365 Tenant ID is not valid. - Microsoft365NotValidClientIdError: If the provided Microsoft365 Client ID is not valid. - Microsoft365NotValidClientSecretError: If the provided Microsoft365 Client Secret is not valid. - Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError: If the provided Microsoft365 Client ID and Client Secret do not belong to the specified Tenant ID. - Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError: If the provided Microsoft365 Tenant ID and Client Secret do not belong to the specified Client ID. - Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError: If the provided Microsoft365 Tenant ID and Client ID do not belong to the specified Client Secret. + M365NotValidTenantIdError: If the provided M365 Tenant ID is not valid. + M365NotValidClientIdError: If the provided M365 Client ID is not valid. + M365NotValidClientSecretError: If the provided M365 Client Secret is not valid. + M365ClientIdAndClientSecretNotBelongingToTenantIdError: If the provided M365 Client ID and Client Secret do not belong to the specified Tenant ID. + M365TenantIdAndClientSecretNotBelongingToClientIdError: If the provided M365 Tenant ID and Client Secret do not belong to the specified Client ID. + M365TenantIdAndClientIdNotBelongingToClientSecretError: If the provided M365 Tenant ID and Client ID do not belong to the specified Client Secret. Returns: dict: A dictionary containing the validated static credentials. @@ -814,72 +921,72 @@ class Microsoft365Provider(Provider): try: UUID(tenant_id) except ValueError: - raise Microsoft365NotValidTenantIdError( + raise M365NotValidTenantIdError( file=os.path.basename(__file__), - message="The provided Microsoft365 Tenant ID is not valid.", + message="The provided M365 Tenant ID is not valid.", ) # Validate the Client ID try: UUID(client_id) except ValueError: - raise Microsoft365NotValidClientIdError( + raise M365NotValidClientIdError( file=os.path.basename(__file__), - message="The provided Microsoft365 Client ID is not valid.", + message="The provided M365 Client ID is not valid.", ) # Validate the Client Secret if not re.match("^[a-zA-Z0-9._~-]+$", client_secret): - raise Microsoft365NotValidClientSecretError( + raise M365NotValidClientSecretError( file=os.path.basename(__file__), - message="The provided Microsoft365 Client Secret is not valid.", + message="The provided M365 Client Secret is not valid.", ) try: - Microsoft365Provider.verify_client(tenant_id, client_id, client_secret) + M365Provider.verify_client(tenant_id, client_id, client_secret) return { "tenant_id": tenant_id, "client_id": client_id, "client_secret": client_secret, } - except Microsoft365NotValidTenantIdError as tenant_id_error: + except M365NotValidTenantIdError as tenant_id_error: logger.error( f"{tenant_id_error.__class__.__name__}[{tenant_id_error.__traceback__.tb_lineno}]: {tenant_id_error}" ) - raise Microsoft365ClientIdAndClientSecretNotBelongingToTenantIdError( + raise M365ClientIdAndClientSecretNotBelongingToTenantIdError( file=os.path.basename(__file__), - message="The provided Microsoft365 Client ID and Client Secret do not belong to the specified Tenant ID.", + message="The provided M365 Client ID and Client Secret do not belong to the specified Tenant ID.", ) - except Microsoft365NotValidClientIdError as client_id_error: + except M365NotValidClientIdError as client_id_error: logger.error( f"{client_id_error.__class__.__name__}[{client_id_error.__traceback__.tb_lineno}]: {client_id_error}" ) - raise Microsoft365TenantIdAndClientSecretNotBelongingToClientIdError( + raise M365TenantIdAndClientSecretNotBelongingToClientIdError( file=os.path.basename(__file__), - message="The provided Microsoft365 Tenant ID and Client Secret do not belong to the specified Client ID.", + message="The provided M365 Tenant ID and Client Secret do not belong to the specified Client ID.", ) - except Microsoft365NotValidClientSecretError as client_secret_error: + except M365NotValidClientSecretError as client_secret_error: logger.error( f"{client_secret_error.__class__.__name__}[{client_secret_error.__traceback__.tb_lineno}]: {client_secret_error}" ) - raise Microsoft365TenantIdAndClientIdNotBelongingToClientSecretError( + raise M365TenantIdAndClientIdNotBelongingToClientSecretError( file=os.path.basename(__file__), - message="The provided Microsoft365 Tenant ID and Client ID do not belong to the specified Client Secret.", + message="The provided M365 Tenant ID and Client ID do not belong to the specified Client Secret.", ) @staticmethod def verify_client(tenant_id, client_id, client_secret) -> None: """ - Verifies the Microsoft365 client credentials using the specified tenant ID, client ID, and client secret. + Verifies the M365 client credentials using the specified tenant ID, client ID, and client secret. Args: - tenant_id (str): The Microsoft365 Active Directory tenant ID. - client_id (str): The Microsoft365 client ID. - client_secret (str): The Microsoft365 client secret. + tenant_id (str): The M365 Active Directory tenant ID. + client_id (str): The M365 client ID. + client_secret (str): The M365 client secret. Raises: - Microsoft365NotValidTenantIdError: If the provided Microsoft365 Tenant ID is not valid. - Microsoft365NotValidClientIdError: If the provided Microsoft365 Client ID is not valid. - Microsoft365NotValidClientSecretError: If the provided Microsoft365 Client Secret is not valid. + M365NotValidTenantIdError: If the provided M365 Tenant ID is not valid. + M365NotValidClientIdError: If the provided M365 Client ID is not valid. + M365NotValidClientSecretError: If the provided M365 Client Secret is not valid. Returns: None @@ -903,17 +1010,17 @@ class Microsoft365Provider(Provider): # Handle specific errors based on the MSAL response error_description = result.get("error_description", "") if f"Tenant '{tenant_id}'" in error_description: - raise Microsoft365NotValidTenantIdError( + raise M365NotValidTenantIdError( file=os.path.basename(__file__), message="The provided Microsoft 365 Tenant ID is not valid for the specified Client ID and Client Secret.", ) if f"Application with identifier '{client_id}'" in error_description: - raise Microsoft365NotValidClientIdError( + raise M365NotValidClientIdError( file=os.path.basename(__file__), message="The provided Microsoft 365 Client ID is not valid for the specified Tenant ID and Client Secret.", ) if "Invalid client secret provided" in error_description: - raise Microsoft365NotValidClientSecretError( + raise M365NotValidClientSecretError( file=os.path.basename(__file__), message="The provided Microsoft 365 Client Secret is not valid for the specified Tenant ID and Client ID.", ) diff --git a/prowler/providers/microsoft365/models.py b/prowler/providers/m365/models.py similarity index 83% rename from prowler/providers/microsoft365/models.py rename to prowler/providers/m365/models.py index c1e028e8d6..f260653555 100644 --- a/prowler/providers/microsoft365/models.py +++ b/prowler/providers/m365/models.py @@ -4,7 +4,7 @@ from prowler.config.config import output_file_timestamp from prowler.providers.common.models import ProviderOutputOptions -class Microsoft365IdentityInfo(BaseModel): +class M365IdentityInfo(BaseModel): identity_id: str = "" identity_type: str = "" tenant_id: str = "" @@ -12,14 +12,22 @@ class Microsoft365IdentityInfo(BaseModel): location: str = "" -class Microsoft365RegionConfig(BaseModel): +class M365RegionConfig(BaseModel): name: str = "" authority: str = None base_url: str = "" credential_scopes: list = [] -class Microsoft365OutputOptions(ProviderOutputOptions): +class M365Credentials(BaseModel): + user: str = "" + passwd: str = "" + client_id: str = "" + client_secret: str = "" + tenant_id: str = "" + + +class M365OutputOptions(ProviderOutputOptions): def __init__(self, arguments, bulk_checks_metadata, identity): # First call Provider_Output_Options init super().__init__(arguments, bulk_checks_metadata) diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/__init__.py b/prowler/providers/m365/services/admincenter/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/__init__.py rename to prowler/providers/m365/services/admincenter/__init__.py diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_client.py b/prowler/providers/m365/services/admincenter/admincenter_client.py similarity index 53% rename from prowler/providers/microsoft365/services/admincenter/admincenter_client.py rename to prowler/providers/m365/services/admincenter/admincenter_client.py index 72facdeefd..a1e3341296 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_client.py +++ b/prowler/providers/m365/services/admincenter/admincenter_client.py @@ -1,6 +1,4 @@ from prowler.providers.common.provider import Provider -from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( - AdminCenter, -) +from prowler.providers.m365.services.admincenter.admincenter_service import AdminCenter admincenter_client = AdminCenter(Provider.get_global_provider()) diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/__init__.py rename to prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/__init__.py diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json rename to prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json index 733298af55..f703c3b594 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json +++ b/prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "admincenter_groups_not_public_visibility", "CheckTitle": "Ensure that only organizationally managed/approved public groups exist", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py b/prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py similarity index 79% rename from prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py rename to prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py index 884d614612..d61fdec68d 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py +++ b/prowler/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.admincenter.admincenter_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( admincenter_client, ) @@ -16,18 +16,18 @@ class admincenter_groups_not_public_visibility(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for groups with public visibility. This method iterates through all groups in Microsoft Admin Center and checks if any group has 'Public' visibility. If so, the check fails for that group. Returns: - List[CheckReportMicrosoft365]: A list containing the results of the check for each group. + List[CheckReportM365]: A list containing the results of the check for each group. """ findings = [] for group in admincenter_client.groups.values(): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=group, resource_name=group.name, diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_service.py b/prowler/providers/m365/services/admincenter/admincenter_service.py similarity index 91% rename from prowler/providers/microsoft365/services/admincenter/admincenter_service.py rename to prowler/providers/m365/services/admincenter/admincenter_service.py index fed450ca82..723c7644d1 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_service.py +++ b/prowler/providers/m365/services/admincenter/admincenter_service.py @@ -5,12 +5,12 @@ from msgraph.generated.models.o_data_errors.o_data_error import ODataError from pydantic import BaseModel from prowler.lib.logger import logger -from prowler.providers.microsoft365.lib.service.service import Microsoft365Service -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider -class AdminCenter(Microsoft365Service): - def __init__(self, provider: Microsoft365Provider): +class AdminCenter(M365Service): + def __init__(self, provider: M365Provider): super().__init__(provider) loop = get_event_loop() @@ -31,7 +31,7 @@ class AdminCenter(Microsoft365Service): self.domains = attributes[2] async def _get_users(self): - logger.info("Microsoft365 - Getting users...") + logger.info("M365 - Getting users...") users = {} try: users_list = await self.client.users.get() @@ -75,7 +75,7 @@ class AdminCenter(Microsoft365Service): return users async def _get_directory_roles(self): - logger.info("Microsoft365 - Getting directory roles...") + logger.info("M365 - Getting directory roles...") directory_roles_with_members = {} try: directory_roles_with_members.update({}) @@ -110,7 +110,7 @@ class AdminCenter(Microsoft365Service): return directory_roles_with_members async def _get_groups(self): - logger.info("Microsoft365 - Getting groups...") + logger.info("M365 - Getting groups...") groups = {} try: groups_list = await self.client.groups.get() @@ -133,7 +133,7 @@ class AdminCenter(Microsoft365Service): return groups async def _get_domains(self): - logger.info("Microsoft365 - Getting domains...") + logger.info("M365 - Getting domains...") domains = {} try: domains_list = await self.client.domains.get() diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/__init__.py rename to prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/__init__.py diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json rename to prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json index a79fc45e94..20ae0d55c0 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json +++ b/prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "admincenter_settings_password_never_expire", "CheckTitle": "Ensure the 'Password expiration policy' is set to 'Set passwords to never expire (recommended)'", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py b/prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py similarity index 81% rename from prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py rename to prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py index fa1ff62265..4af24427ea 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py +++ b/prowler/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.admincenter.admincenter_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( admincenter_client, ) @@ -17,19 +17,19 @@ class admincenter_settings_password_never_expire(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for password never expires policy. This method iterates over all domains and checks if the password validity period is set to `2147483647`, indicating that passwords for users in the domain never expire. Returns: - List[CheckReportMicrosoft365]: A list of reports indicating whether the domain's password + List[CheckReportM365]: A list of reports indicating whether the domain's password policy is set to never expire. """ findings = [] for domain in admincenter_client.domains.values(): - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=domain, resource_name=domain.id, diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/__init__.py rename to prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/__init__.py diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json rename to prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json index 563dd09157..e39c14ca71 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json +++ b/prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "admincenter_users_admins_reduced_license_footprint", "CheckTitle": "Ensure administrative accounts use licenses with a reduced application footprint", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py b/prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py similarity index 86% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py rename to prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py index 9d57e3cbc2..7497feb305 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py +++ b/prowler/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.admincenter.admincenter_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( admincenter_client, ) @@ -17,7 +17,7 @@ class admincenter_users_admins_reduced_license_footprint(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for users with administrative roles and their licenses. This method iterates over all users and checks if those with administrative roles @@ -25,7 +25,7 @@ class admincenter_users_admins_reduced_license_footprint(Check): the check passes; otherwise, it fails. Returns: - List[CheckReportMicrosoft365]: A list containing the result of the check for each user. + List[CheckReportM365]: A list containing the result of the check for each user. """ findings = [] allowed_licenses = ["AAD_PREMIUM", "AAD_PREMIUM_P2"] @@ -39,7 +39,7 @@ class admincenter_users_admins_reduced_license_footprint(Check): ) if admin_roles: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=user, resource_name=user.name, diff --git a/prowler/providers/microsoft365/services/entra/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/__init__.py rename to prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/__init__.py diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json rename to prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json index 2ffc185f91..8591295973 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json +++ b/prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "admincenter_users_between_two_and_four_global_admins", "CheckTitle": "Ensure that between two and four global admins are designated", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py b/prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py similarity index 83% rename from prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py rename to prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py index 0abebdce31..d584bc8a32 100644 --- a/prowler/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py +++ b/prowler/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.admincenter.admincenter_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( admincenter_client, ) @@ -16,21 +16,21 @@ class admincenter_users_between_two_and_four_global_admins(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for the number of Global Administrators. This method checks if the number of users with the 'Global Administrator' role is between two and four. If the condition is met, the check passes; otherwise, it fails. Returns: - List[CheckReportMicrosoft365]: A list containing the result of the check for the Global Administrators. + List[CheckReportM365]: A list containing the result of the check for the Global Administrators. """ findings = [] directory_roles = admincenter_client.directory_roles global_admin_role = directory_roles.get("Global Administrator", {}) if global_admin_role: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=global_admin_role, resource_name=global_admin_role.name, diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/__init__.py b/prowler/providers/m365/services/entra/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/__init__.py rename to prowler/providers/m365/services/entra/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/__init__.py b/prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json index a70b98501a..ef4f550307 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_consent_workflow_enabled", "CheckTitle": "Ensure the admin consent workflow is enabled.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py b/prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py similarity index 86% rename from prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py rename to prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py index 24bcbe9c47..5a22c343ce 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py +++ b/prowler/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_admin_consent_workflow_enabled(Check): @@ -17,7 +17,7 @@ class entra_admin_consent_workflow_enabled(Check): from accessing critical applications or forced to use insecure workarounds. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the admin consent workflow requirement check. @@ -25,12 +25,12 @@ class entra_admin_consent_workflow_enabled(Check): whether the admin consent workflow is enabled. Returns: - List[CheckReportMicrosoft365]: A list containing the report with the result of the check. + List[CheckReportM365]: A list containing the report with the result of the check. """ findings = [] admin_consent_policy = entra_client.admin_consent_policy if admin_consent_policy: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=admin_consent_policy, resource_name="Admin Consent Policy", diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/__init__.py b/prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json b/prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json index 41ba6ba9ce..06f70fcba4 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_portals_access_restriction", "CheckTitle": "Ensure that only administrative roles have access to Microsoft Admin Portals", "CheckAliases": [ diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py b/prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py rename to prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py index a8f744ec4a..23f6e3288a 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py +++ b/prowler/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( AdminRoles, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -13,15 +13,15 @@ class entra_admin_portals_access_restriction(Check): This check ensures that Conditional Access policies are in place to deny access to the Microsoft 365 admin center for users with limited access roles. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that Conditional Access policies deny access to the Microsoft 365 admin center for users with limited access roles. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -52,7 +52,7 @@ class entra_admin_portals_access_restriction(Check): ConditionalAccessGrantControl.BLOCK in policy.grant_controls.built_in_controls ): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_admin_users_cloud_only/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_users_cloud_only/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json b/prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json similarity index 81% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json index e507677a0d..4e7a5f4574 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_users_cloud_only", "CheckTitle": "Ensure all Microsoft 365 administrative users are cloud-only", "CheckType": [], @@ -15,7 +15,7 @@ "Code": { "CLI": "", "NativeIaC": "", - "Other": "1. Identify on-premises synchronized administrative users using Microsoft Entra Connect or equivalent tools.\n2. Create new cloud-only administrative user with appropriate permissions.\n3. Migrate administrative tasks from on-premises synchronized users to the new cloud-only user.\n4. Disable or remove the on-premises synchronized administrative users.", + "Other": "1. Identify on-premises synchronized administrative users using Microsoft Entra Connect or equivalent tools. 2. Create new cloud-only administrative user with appropriate permissions. 3. Migrate administrative tasks from on-premises synchronized users to the new cloud-only user. 4. Disable or remove the on-premises synchronized administrative users.", "Terraform": "" }, "Recommendation": { diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py b/prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py similarity index 78% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py rename to prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py index 7ea617ca0e..c41699337c 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py +++ b/prowler/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only.py @@ -1,8 +1,8 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import AdminRoles +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import AdminRoles class entra_admin_users_cloud_only(Check): @@ -12,11 +12,11 @@ class entra_admin_users_cloud_only(Check): If such users are found, the check will fail. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the check to identify admin accounts with non-cloud-only accounts. Returns: - List[CheckReportMicrosoft365]: A list containing the check report with the status and details. + List[CheckReportM365]: A list containing the check report with the status and details. """ findings = [] if entra_client.users: @@ -29,7 +29,7 @@ class entra_admin_users_cloud_only(Check): ): non_cloud_admins.append(user_id) - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Cloud-only account", diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json index 63f312be10..84f12d6b48 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_users_mfa_enabled", "CheckTitle": "Ensure multifactor authentication is enabled for all users in administrative roles.", "CheckAliases": [ diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py b/prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py similarity index 85% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py rename to prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py index e668ffd11a..dff536999b 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py +++ b/prowler/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled.py @@ -1,8 +1,8 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( AdminRoles, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -20,7 +20,7 @@ class entra_admin_users_mfa_enabled(Check): The check fails if no enabled policy is found that requires MFA for any administrative role. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the admin MFA requirement check for administrative roles. @@ -28,11 +28,11 @@ class entra_admin_users_mfa_enabled(Check): indicating whether MFA is enforced for users in administrative roles. Returns: - List[CheckReportMicrosoft365]: A list containing a single report with the result of the check. + List[CheckReportM365]: A list containing a single report with the result of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -62,7 +62,7 @@ class entra_admin_users_mfa_enabled(Check): ConditionalAccessGrantControl.MFA in policy.grant_controls.built_in_controls ): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=entra_client.conditional_access_policies, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json index 3aacb2c1ac..0865121916 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_users_phishing_resistant_mfa_enabled", "CheckTitle": "Ensure phishing-resistant MFA strength is required for all administrator accounts", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py b/prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py rename to prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py index 97022161f7..6f0fbc281d 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py +++ b/prowler/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( AdminRoles, AuthenticationStrength, ConditionalAccessPolicyState, @@ -10,14 +10,14 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( class entra_admin_users_phishing_resistant_mfa_enabled(Check): """Check if Conditional Access policies require Phishing-resistant MFA strength for admin users.""" - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that Conditional Access policies require Phishing-resistant MFA strength for admin users. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -49,7 +49,7 @@ class entra_admin_users_phishing_resistant_mfa_enabled(Check): and policy.grant_controls.authentication_strength == AuthenticationStrength.PHISHING_RESISTANT_MFA ): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/__init__.py b/prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/__init__.py rename to prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json index c7dd5caa40..859e15dabc 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_admin_users_sign_in_frequency_enabled", "CheckTitle": "Ensure Sign-in frequency periodic reauthentication is enabled and properly configured.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py b/prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py similarity index 91% rename from prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py rename to prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py index 38558fc0f3..3e63d16f32 100644 --- a/prowler/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py +++ b/prowler/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( AdminRoles, ConditionalAccessPolicyState, SignInFrequencyInterval, @@ -11,10 +11,10 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( class entra_admin_users_sign_in_frequency_enabled(Check): """Check if Conditional Access policies enforce sign-in frequency for admin users.""" - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Validate sign-in frequency enforcement for admin users.""" findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -40,7 +40,7 @@ class entra_admin_users_sign_in_frequency_enabled(Check): ): continue - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_client.py b/prowler/providers/m365/services/entra/entra_client.py similarity index 58% rename from prowler/providers/microsoft365/services/entra/entra_client.py rename to prowler/providers/m365/services/entra/entra_client.py index 1a3b921adf..84c60b40fd 100644 --- a/prowler/providers/microsoft365/services/entra/entra_client.py +++ b/prowler/providers/m365/services/entra/entra_client.py @@ -1,4 +1,4 @@ from prowler.providers.common.provider import Provider -from prowler.providers.microsoft365.services.entra.entra_service import Entra +from prowler.providers.m365.services.entra.entra_service import Entra entra_client = Entra(Provider.get_global_provider()) diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json b/prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json rename to prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json index 55c2916196..efa0c5b6dc 100644 --- a/prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json +++ b/prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_dynamic_group_for_guests_created", "CheckTitle": "Ensure a dynamic group for guest users is created.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py b/prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py rename to prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py index 9bd70f624c..f4ba9ff616 100644 --- a/prowler/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py +++ b/prowler/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_dynamic_group_for_guests_created(Check): @@ -14,7 +14,7 @@ class entra_dynamic_group_for_guests_created(Check): automated enforcement of conditional access policies and reduces manual management of guest access. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the dynamic group for guest users check. @@ -22,7 +22,7 @@ class entra_dynamic_group_for_guests_created(Check): indicating whether at least one dynamic group exists with a membership rule targeting guest users. Returns: - List[CheckReportMicrosoft365]: A list containing a single report with the result of the check. + List[CheckReportM365]: A list containing a single report with the result of the check. """ findings = [] if entra_client.groups: @@ -33,7 +33,7 @@ class entra_dynamic_group_for_guests_created(Check): dynamic_group = group break - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=dynamic_group if dynamic_group else {}, resource_name=dynamic_group.name if dynamic_group else "Group", diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json index 039071202c..bb524cfb98 100644 --- a/prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_identity_protection_sign_in_risk_enabled", "CheckTitle": "Ensure that Identity Protection sign-in risk policies are enabled", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py b/prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py similarity index 86% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py rename to prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py index 29b33cdc3e..c9878c8315 100644 --- a/prowler/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py +++ b/prowler/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessGrantControl, ConditionalAccessPolicyState, RiskLevel, @@ -14,15 +14,15 @@ class entra_identity_protection_sign_in_risk_enabled(Check): This check ensures that at least one Conditional Access policy is a Identity Protection sign-in risk policy. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that at least one Conditional Access policy is a Identity Protection sign-in risk policy. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -56,7 +56,7 @@ class entra_identity_protection_sign_in_risk_enabled(Check): ): continue - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/__init__.py b/prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/__init__.py rename to prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json index 04f94276b9..a36bec74f9 100644 --- a/prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_identity_protection_user_risk_enabled", "CheckTitle": "Ensure that Identity Protection user risk policies are enabled", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py b/prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py similarity index 86% rename from prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py rename to prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py index f6cb547474..8864663e68 100644 --- a/prowler/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py +++ b/prowler/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessGrantControl, ConditionalAccessPolicyState, GrantControlOperator, @@ -14,15 +14,15 @@ class entra_identity_protection_user_risk_enabled(Check): This check ensures that at least one Conditional Access policy is a Identity Protection user risk policy. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that at least one Conditional Access policy is a Identity Protection user risk policy. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -54,7 +54,7 @@ class entra_identity_protection_user_risk_enabled(Check): continue if policy.conditions.user_risk_levels: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/__init__.py b/prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/__init__.py rename to prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json b/prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json rename to prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json index 31ab36f686..eb4783c8ae 100644 --- a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json +++ b/prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_legacy_authentication_blocked", "CheckTitle": "Ensure that Conditional Access policy blocks legacy authentication", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py b/prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py rename to prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py index ee14720618..f625cb6182 100644 --- a/prowler/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py +++ b/prowler/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ClientAppType, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -13,14 +13,14 @@ class entra_legacy_authentication_blocked(Check): This check ensures that at least one Conditional Access policy blocks legacy authentication. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that at least one Conditional Access policy blocks legacy authentication. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -55,7 +55,7 @@ class entra_legacy_authentication_blocked(Check): ConditionalAccessGrantControl.BLOCK in policy.grant_controls.built_in_controls ): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py b/prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json b/prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json index abaf961476..3f97198061 100644 --- a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json +++ b/prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_managed_device_required_for_authentication", "CheckTitle": "Ensure that only managed devices are required for authentication", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py b/prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py index 6825725a52..c8a8845bd9 100644 --- a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py +++ b/prowler/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessGrantControl, ConditionalAccessPolicyState, GrantControlOperator, @@ -13,15 +13,15 @@ class entra_managed_device_required_for_authentication(Check): This check ensures that Conditional Access policies are in place to enforce managed device requirement for authentication. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that Conditional Access policies enforce managed device requirement for authentication. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -54,7 +54,7 @@ class entra_managed_device_required_for_authentication(Check): continue if policy.grant_controls.operator == GrantControlOperator.OR: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json b/prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json index 871d9f318e..59d2e46d82 100644 --- a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json +++ b/prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_managed_device_required_for_mfa_registration", "CheckTitle": "Ensure that only managed devices are required for MFA registration", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py b/prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py similarity index 84% rename from prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py rename to prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py index 7fc446c956..ee5336a4fd 100644 --- a/prowler/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py +++ b/prowler/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration.py @@ -1,6 +1,6 @@ -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessGrantControl, ConditionalAccessPolicyState, GrantControlOperator, @@ -14,15 +14,15 @@ class entra_managed_device_required_for_mfa_registration(Check): This check ensures that Conditional Access policies are in place to enforce MFA registration on a managed device. """ - def execute(self) -> list[CheckReportMicrosoft365]: + def execute(self) -> list[CheckReportM365]: """Execute the check to ensure that Conditional Access policies enforce MFA registration on a managed device. Returns: - list[CheckReportMicrosoft365]: A list containing the results of the check. + list[CheckReportM365]: A list containing the results of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -53,7 +53,7 @@ class entra_managed_device_required_for_mfa_registration(Check): continue if policy.grant_controls.operator == GrantControlOperator.OR: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=policy, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/__init__.py b/prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/__init__.py rename to prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json index 9966b06066..373e44f042 100644 --- a/prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_password_hash_sync_enabled", "CheckTitle": "Ensure that password hash sync is enabled for hybrid deployments.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py b/prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py similarity index 82% rename from prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py rename to prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py index 57d4868fc3..25ece6283d 100644 --- a/prowler/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py +++ b/prowler/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_password_hash_sync_enabled(Check): @@ -16,7 +16,7 @@ class entra_password_hash_sync_enabled(Check): Note: This control applies only to hybrid deployments using Microsoft Entra Connect sync and does not apply to federated domains. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the password hash synchronization requirement check. @@ -24,11 +24,11 @@ class entra_password_hash_sync_enabled(Check): password hash synchronization is enabled. Returns: - List[CheckReportMicrosoft365]: A list containing the report object with the result of the check. + List[CheckReportM365]: A list containing the report object with the result of the check. """ findings = [] for organization in entra_client.organizations: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=organization, resource_id=organization.id, diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py b/prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py rename to prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json b/prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json rename to prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json index df7e7f30db..47a1658322 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json +++ b/prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_policy_ensure_default_user_cannot_create_tenants", "CheckTitle": "Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes'", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py b/prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py similarity index 82% rename from prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py rename to prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py index de2c2112eb..4a8c822b48 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py +++ b/prowler/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_policy_ensure_default_user_cannot_create_tenants(Check): @@ -14,7 +14,7 @@ class entra_policy_ensure_default_user_cannot_create_tenants(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for tenant creation restrictions. This method examines the authorization policy settings to determine if @@ -22,12 +22,12 @@ class entra_policy_ensure_default_user_cannot_create_tenants(Check): restricted, the check passes. Returns: - List[Check_Report_Microsoft365]: A list containing the result of the check. + List[Check_Report_M365]: A list containing the result of the check. """ findings = [] auth_policy = entra_client.authorization_policy - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=auth_policy if auth_policy else {}, resource_name=auth_policy.name if auth_policy else "Authorization Policy", diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py b/prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py rename to prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json b/prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json rename to prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json index ffd4e74d5e..9e77161921 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json +++ b/prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_policy_guest_invite_only_for_admin_roles", "CheckTitle": "Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py b/prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py similarity index 80% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py rename to prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py index 6dfb7b5e36..710b5c524d 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py +++ b/prowler/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py @@ -1,8 +1,8 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import InvitationsFrom +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import InvitationsFrom class entra_policy_guest_invite_only_for_admin_roles(Check): @@ -13,7 +13,7 @@ class entra_policy_guest_invite_only_for_admin_roles(Check): are limited accordingly. Otherwise, they are not restricted. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the guest invitation restriction check. @@ -22,13 +22,13 @@ class entra_policy_guest_invite_only_for_admin_roles(Check): specific administrative roles only. Returns: - List[CheckReportMicrosoft365]: A list containing a single check report that + List[CheckReportM365]: A list containing a single check report that details the pass/fail status and description. """ findings = [] auth_policy = entra_client.authorization_policy - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=auth_policy if auth_policy else {}, resource_name=auth_policy.name if auth_policy else "Authorization Policy", diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py b/prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py rename to prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json b/prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json rename to prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json index 06445080c7..c6482d6883 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json +++ b/prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_policy_guest_users_access_restrictions", "CheckTitle": "Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py b/prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py similarity index 79% rename from prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py rename to prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py index 2e431c0cd9..8669135970 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py +++ b/prowler/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py @@ -1,8 +1,8 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import AuthPolicyRoles +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import AuthPolicyRoles class entra_policy_guest_users_access_restrictions(Check): @@ -12,22 +12,22 @@ class entra_policy_guest_users_access_restrictions(Check): are limited to accessing only the properties and memberships of their own directory objects. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the guest user access restriction check. - This method retrieves the authorization policy from the Microsoft365 Entra client, + This method retrieves the authorization policy from the M365 Entra client, and then checks if the 'guest_user_role_id' matches the predefined restricted role ID. If it matches, the check passes; otherwise, it fails. Returns: - List[CheckReportMicrosoft365]: A list containing a single check report detailing + List[CheckReportM365]: A list containing a single check report detailing the status and details of the guest user access restriction. """ findings = [] auth_policy = entra_client.authorization_policy - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=auth_policy if auth_policy else {}, resource_name=auth_policy.name if auth_policy else "Authorization Policy", diff --git a/prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/__init__.py b/prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/__init__.py rename to prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json b/prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json rename to prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json index 066cb1fa77..ac38009fff 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json +++ b/prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_policy_restricts_user_consent_for_apps", "CheckTitle": "Ensure 'User consent for applications' is set to 'Do not allow user consent'", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py b/prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py similarity index 82% rename from prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py rename to prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py index a8ac22f008..1d54ab41df 100644 --- a/prowler/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py +++ b/prowler/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_policy_restricts_user_consent_for_apps(Check): @@ -12,16 +12,16 @@ class entra_policy_restricts_user_consent_for_apps(Check): If such consent is disabled, the check passes. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check for user consent restrictions. Returns: - List[CheckReportMicrosoft365]: A list containing the result of the check. + List[CheckReportM365]: A list containing the result of the check. """ findings = [] auth_policy = entra_client.authorization_policy - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=auth_policy if auth_policy else {}, resource_name=auth_policy.name if auth_policy else "Authorization Policy", diff --git a/prowler/providers/microsoft365/services/entra/entra_service.py b/prowler/providers/m365/services/entra/entra_service.py similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_service.py rename to prowler/providers/m365/services/entra/entra_service.py index 16594a8941..d752562023 100644 --- a/prowler/providers/microsoft365/services/entra/entra_service.py +++ b/prowler/providers/m365/services/entra/entra_service.py @@ -7,12 +7,12 @@ from uuid import UUID from pydantic import BaseModel from prowler.lib.logger import logger -from prowler.providers.microsoft365.lib.service.service import Microsoft365Service -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider -class Entra(Microsoft365Service): - def __init__(self, provider: Microsoft365Provider): +class Entra(M365Service): + def __init__(self, provider: M365Provider): super().__init__(provider) loop = get_event_loop() diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/__init__.py b/prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/__init__.py rename to prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json b/prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json rename to prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json index 59676ee664..5cc28bd7ae 100644 --- a/prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json +++ b/prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_thirdparty_integrated_apps_not_allowed", "CheckTitle": "Ensure third party integrated applications are not allowed", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py b/prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py similarity index 83% rename from prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py rename to prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py index 36ce95286c..5927990dbf 100644 --- a/prowler/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py +++ b/prowler/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client class entra_thirdparty_integrated_apps_not_allowed(Check): @@ -14,20 +14,20 @@ class entra_thirdparty_integrated_apps_not_allowed(Check): metadata: Metadata associated with the check (inherited from Check). """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """Execute the check to ensure third-party integrated apps are not allowed for non-admin users. This method checks if the authorization policy allows non-admin users to create apps. If the policy allows app creation, the check fails. Otherwise, the check passes. Returns: - List[CheckReportMicrosoft365]: A list containing the result of the check for app creation policy. + List[CheckReportM365]: A list containing the result of the check for app creation policy. """ findings = [] auth_policy = entra_client.authorization_policy if auth_policy: - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=auth_policy if auth_policy else {}, resource_name=( diff --git a/prowler/providers/microsoft365/services/sharepoint/__init__.py b/prowler/providers/m365/services/entra/entra_users_mfa_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/sharepoint/__init__.py rename to prowler/providers/m365/services/entra/entra_users_mfa_enabled/__init__.py diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json b/prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json rename to prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json index 75f82197c5..1d2e25f29d 100644 --- a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json +++ b/prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "entra_users_mfa_enabled", "CheckTitle": "Ensure multifactor authentication is enabled for all users.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py b/prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py similarity index 83% rename from prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py rename to prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py index 8159c3ebc4..a87d1edec3 100644 --- a/prowler/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py +++ b/prowler/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled.py @@ -1,8 +1,8 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.entra.entra_client import entra_client -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client +from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessGrantControl, ConditionalAccessPolicyState, ) @@ -18,7 +18,7 @@ class entra_users_mfa_enabled(Check): The check fails if no enabled policy is found that requires MFA for all users. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the admin MFA requirement check for all users. @@ -26,11 +26,11 @@ class entra_users_mfa_enabled(Check): indicating whether MFA is enforced for users in all users. Returns: - List[CheckReportMicrosoft365]: A list containing a single report with the result of the check. + List[CheckReportM365]: A list containing a single report with the result of the check. """ findings = [] - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource={}, resource_name="Conditional Access Policies", @@ -59,7 +59,7 @@ class entra_users_mfa_enabled(Check): ConditionalAccessGrantControl.MFA in policy.grant_controls.built_in_controls ): - report = CheckReportMicrosoft365( + report = CheckReportM365( metadata=self.metadata(), resource=entra_client.conditional_access_policies, resource_name=policy.display_name, diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/__init__.py b/prowler/providers/m365/services/purview/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/__init__.py rename to prowler/providers/m365/services/purview/__init__.py diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/__init__.py b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/__init__.py rename to prowler/providers/m365/services/purview/purview_audit_log_search_enabled/__init__.py diff --git a/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.metadata.json b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.metadata.json new file mode 100644 index 0000000000..ef49cfa524 --- /dev/null +++ b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "purview_audit_log_search_enabled", + "CheckTitle": "Ensure Purview audit log search is enabled", + "CheckType": [], + "ServiceName": "purview", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Purview Settings", + "Description": "Ensure Purview audit log search is enabled.", + "Risk": "Disabling Microsoft 365 audit log search can hinder the ability to track and monitor user and admin activities, making it harder to detect suspicious behavior, security incidents, or compliance violations. This can result in undetected breaches and inability to respond to incidents effectively.", + "RelatedUrl": "https://learn.microsoft.com/en-us/purview/audit-search?tabs=microsoft-purview-portal", + "Remediation": { + "Code": { + "CLI": "Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Purview https://compliance.microsoft.com. 2. Select Audit to open the audit search. 3. Click Start recording user and admin activity next to the information warning at the top. 4. Click Yes on the dialog box to confirm.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that Microsoft 365 audit log search is enabled to maintain a comprehensive record of user and admin activities. This will help improve security monitoring, support compliance needs, and provide critical insights for responding to incidents.", + "Url": "https://learn.microsoft.com/en-us/purview/audit-search?tabs=microsoft-purview-portal" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py new file mode 100644 index 0000000000..f6884dbfcf --- /dev/null +++ b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py @@ -0,0 +1,41 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.purview.purview_client import purview_client + + +class purview_audit_log_search_enabled(Check): + """Check if Purview audit log search is enabled. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for audit log search + + This method checks if audit log search is enabled Purview settings + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + audit_log_config = purview_client.audit_log_config + report = CheckReportM365( + metadata=self.metadata(), + resource=audit_log_config if audit_log_config else {}, + resource_name="Purview Settings", + resource_id="purviewSettings", + ) + report.status = "FAIL" + report.status_extended = "Purview audit log search is not enabled." + + if purview_client.audit_log_config and getattr( + purview_client.audit_log_config, "audit_log_search", False + ): + report.status = "PASS" + report.status_extended = "Purview audit log search is enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/purview/purview_client.py b/prowler/providers/m365/services/purview/purview_client.py new file mode 100644 index 0000000000..dea423b967 --- /dev/null +++ b/prowler/providers/m365/services/purview/purview_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.m365.services.purview.purview_service import Purview + +purview_client = Purview(Provider.get_global_provider()) diff --git a/prowler/providers/m365/services/purview/purview_service.py b/prowler/providers/m365/services/purview/purview_service.py new file mode 100644 index 0000000000..5d6fdfce36 --- /dev/null +++ b/prowler/providers/m365/services/purview/purview_service.py @@ -0,0 +1,33 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider + + +class Purview(M365Service): + def __init__(self, provider: M365Provider): + super().__init__(provider) + self.powershell.connect_exchange_online() + self.audit_log_config = self._get_audit_log_config() + self.powershell.close() + + def _get_audit_log_config(self): + logger.info("M365 - Getting Admin Audit Log settings...") + audit_log_config = None + try: + audit_log_config_response = self.powershell.get_audit_log_config() + audit_log_config = AuditLogConfig( + audit_log_search=audit_log_config_response.get( + "UnifiedAuditLogIngestionEnabled", False + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return audit_log_config + + +class AuditLogConfig(BaseModel): + audit_log_search: bool diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/__init__.py b/prowler/providers/m365/services/sharepoint/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/__init__.py rename to prowler/providers/m365/services/sharepoint/__init__.py diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_client.py b/prowler/providers/m365/services/sharepoint/sharepoint_client.py similarity index 53% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_client.py rename to prowler/providers/m365/services/sharepoint/sharepoint_client.py index fc547bc167..be3cf6377b 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_client.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_client.py @@ -1,6 +1,4 @@ from prowler.providers.common.provider import Provider -from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( - SharePoint, -) +from prowler.providers.m365.services.sharepoint.sharepoint_service import SharePoint sharepoint_client = SharePoint(Provider.get_global_provider()) diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/__init__.py b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/__init__.py rename to prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/__init__.py diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json rename to prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json index ee559a57a0..dbc758be2c 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json +++ b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "sharepoint_external_sharing_managed", "CheckTitle": "Ensure SharePoint external sharing is managed through domain whitelists/blacklists.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py similarity index 88% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py rename to prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py index 9fd8c432a1..087d9a2540 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.sharepoint.sharepoint_client import ( sharepoint_client, ) @@ -19,7 +19,7 @@ class sharepoint_external_sharing_managed(Check): of verifying that the allowed/blocked domain list is not empty. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the SharePoint external sharing management check. @@ -27,12 +27,12 @@ class sharepoint_external_sharing_managed(Check): generates a report indicating whether external sharing is managed via domain restrictions. Returns: - List[CheckReportMicrosoft365]: A list containing a report with the result of the check. + List[CheckReportM365]: A list containing a report with the result of the check. """ findings = [] settings = sharepoint_client.settings if settings: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=settings if settings else {}, resource_name="SharePoint Settings", diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/__init__.py b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json rename to prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json index 63b040672d..5b9426131d 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json +++ b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "sharepoint_external_sharing_restricted", "CheckTitle": "Ensure external content sharing is restricted.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py similarity index 83% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py rename to prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py index 639ce00df3..728231a22f 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.sharepoint.sharepoint_client import ( sharepoint_client, ) @@ -15,7 +15,7 @@ class sharepoint_external_sharing_restricted(Check): setting is used, legacy sharing may be allowed, increasing the risk of unauthorized data access. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the SharePoint external sharing restriction check. @@ -23,12 +23,12 @@ class sharepoint_external_sharing_restricted(Check): indicating whether external sharing is restricted to 'New and existing guests' (ExternalUserSharingOnly). Returns: - List[Check_Report_Microsoft365]: A list containing a report with the result of the check. + List[Check_Report_M365]: A list containing a report with the result of the check. """ findings = [] settings = sharepoint_client.settings if settings: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=settings if settings else {}, resource_name="SharePoint Settings", diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/__init__.py b/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json b/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json rename to prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json index 89acd7e46a..9eba868289 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json +++ b/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "sharepoint_guest_sharing_restricted", "CheckTitle": "Ensure that SharePoint guest users cannot share items they don't own.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py b/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py similarity index 81% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py rename to prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py index 3666a837b1..ff66780a87 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.sharepoint.sharepoint_client import ( sharepoint_client, ) @@ -16,7 +16,7 @@ class sharepoint_guest_sharing_restricted(Check): to prevent external users from resharing is enabled. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the SharePoint guest sharing restriction check. @@ -24,12 +24,12 @@ class sharepoint_guest_sharing_restricted(Check): and generates a report indicating whether guest users are prevented from sharing items they do not own. Returns: - List[CheckReportMicrosoft365]: A list containing a report with the result of the check. + List[CheckReportM365]: A list containing a report with the result of the check. """ findings = [] settings = sharepoint_client.settings if settings: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=settings if settings else {}, resource_name="SharePoint Settings", diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/__init__.py b/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json b/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json similarity index 98% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json rename to prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json index e9c0047115..ec7355bda0 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json +++ b/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.metadata.json @@ -1,5 +1,5 @@ { - "Provider": "microsoft365", + "Provider": "m365", "CheckID": "sharepoint_modern_authentication_required", "CheckTitle": "Ensure modern authentication for SharePoint applications is required.", "CheckType": [], diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py b/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py similarity index 83% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py rename to prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py index 04f61084b2..6d5761ca35 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required.py @@ -1,7 +1,7 @@ from typing import List -from prowler.lib.check.models import Check, CheckReportMicrosoft365 -from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import ( +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.sharepoint.sharepoint_client import ( sharepoint_client, ) @@ -18,7 +18,7 @@ class sharepoint_modern_authentication_required(Check): The check fails if modern authentication is not enforced, indicating that legacy protocols may be used. """ - def execute(self) -> List[CheckReportMicrosoft365]: + def execute(self) -> List[CheckReportM365]: """ Execute the SharePoint modern authentication requirement check. @@ -26,12 +26,12 @@ class sharepoint_modern_authentication_required(Check): generates a report indicating whether modern authentication is required for SharePoint applications. Returns: - List[CheckReportMicrosoft365]: A list containing the report object with the result of the check. + List[CheckReportM365]: A list containing the report object with the result of the check. """ findings = [] settings = sharepoint_client.settings if settings: - report = CheckReportMicrosoft365( + report = CheckReportM365( self.metadata(), resource=settings if settings else {}, resource_name="SharePoint Settings", diff --git a/prowler/providers/microsoft365/services/sharepoint/sharepoint_service.py b/prowler/providers/m365/services/sharepoint/sharepoint_service.py similarity index 85% rename from prowler/providers/microsoft365/services/sharepoint/sharepoint_service.py rename to prowler/providers/m365/services/sharepoint/sharepoint_service.py index bb8f2c6903..6040a321b8 100644 --- a/prowler/providers/microsoft365/services/sharepoint/sharepoint_service.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_service.py @@ -5,12 +5,12 @@ from msgraph.generated.models.o_data_errors.o_data_error import ODataError from pydantic import BaseModel from prowler.lib.logger import logger -from prowler.providers.microsoft365.lib.service.service import Microsoft365Service -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider -class SharePoint(Microsoft365Service): - def __init__(self, provider: Microsoft365Provider): +class SharePoint(M365Service): + def __init__(self, provider: M365Provider): super().__init__(provider) loop = get_event_loop() self.tenant_domain = provider.identity.tenant_domain @@ -22,7 +22,7 @@ class SharePoint(Microsoft365Service): self.settings = attributes[0] async def _get_settings(self): - logger.info("Microsoft365 - Getting SharePoint global settings...") + logger.info("M365 - Getting SharePoint global settings...") settings = None try: global_settings = await self.client.admin.sharepoint.settings.get() diff --git a/prowler/providers/m365/services/teams/__init__.py b/prowler/providers/m365/services/teams/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_client.py b/prowler/providers/m365/services/teams/teams_client.py new file mode 100644 index 0000000000..9727500d7d --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.m365.services.teams.teams_service import Teams + +teams_client = Teams(Provider.get_global_provider()) diff --git a/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/__init__.py b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.metadata.json b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.metadata.json new file mode 100644 index 0000000000..f433685c62 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_external_file_sharing_restricted", + "CheckTitle": "Ensure external file sharing in Teams is enabled for only approved cloud storage services", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Settings", + "Description": "", + "Risk": "Allowing unrestricted third-party cloud storage services in Teams increases the risk of data exfiltration, compliance violations, and unauthorized access to sensitive information. Users may store or share data through unapproved platforms with weaker security controls.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/get-csteamsclientconfiguration?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsClientConfiguration -AllowGoogleDrive $false -AllowShareFile $false -AllowBox $false -AllowDropBox $false -AllowEgnyte $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Teams select Teams settings. 3. Set any unauthorized providers to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict external file sharing in Teams to only approved cloud storage providers, such as SharePoint Online and OneDrive. Configure Teams policies to block unauthorized services and enforce compliance with organizational data protection standards.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/get-csteamsclientconfiguration?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py new file mode 100644 index 0000000000..2ec8cc87f8 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py @@ -0,0 +1,67 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client +from prowler.providers.m365.services.teams.teams_service import CloudStorageSettings + + +class teams_external_file_sharing_restricted(Check): + """Check if external file sharing is restricted in Teams. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for external file sharing settings in Teams. + + This method checks if external file sharing is restricted in Teams. If external file sharing + is restricted to only approved cloud storage services the check passes; otherwise, it fails. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + cloud_storage_settings = teams_client.teams_settings.cloud_storage_settings + report = CheckReportM365( + metadata=self.metadata(), + resource=cloud_storage_settings if cloud_storage_settings else {}, + resource_name="Cloud Storage Settings", + resource_id="cloudStorageSettings", + ) + report.status = "FAIL" + report.status_extended = "External file sharing is not restricted to only approved cloud storage services." + + allowed_services = teams_client.audit_config.get( + "allowed_cloud_storage_services", [] + ) + if cloud_storage_settings: + # Get storage services from CloudStorageSettings class items + storage_services = [ + attr + for attr, type in CloudStorageSettings.__annotations__.items() + if type is bool + ] + + # Check if all services are disabled when no allowed services are specified + # or if all enabled services are in the allowed list + if ( + not allowed_services + and all( + not getattr(cloud_storage_settings, service, True) + for service in storage_services + ) + ) or ( + allowed_services + and not any( + getattr(cloud_storage_settings, service, True) + and service not in allowed_services + for service in storage_services + ) + ): + report.status = "PASS" + report.status_extended = "External file sharing is restricted to only approved cloud storage services." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py new file mode 100644 index 0000000000..1415b6118b --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -0,0 +1,45 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider + + +class Teams(M365Service): + def __init__(self, provider: M365Provider): + super().__init__(provider) + self.powershell.connect_microsoft_teams() + self.teams_settings = self._get_teams_client_configuration() + self.powershell.close() + + def _get_teams_client_configuration(self): + logger.info("M365 - Getting Teams settings...") + settings = self.powershell.get_teams_settings() + try: + teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=settings.get("AllowBox", True), + allow_drop_box=settings.get("AllowDropBox", True), + allow_egnyte=settings.get("AllowEgnyte", True), + allow_google_drive=settings.get("AllowGoogleDrive", True), + allow_share_file=settings.get("AllowShareFile", True), + ) + ) + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return teams_settings + + +class CloudStorageSettings(BaseModel): + allow_box: bool + allow_drop_box: bool + allow_egnyte: bool + allow_google_drive: bool + allow_share_file: bool + + +class TeamsSettings(BaseModel): + cloud_storage_settings: CloudStorageSettings diff --git a/prowler/providers/microsoft365/lib/arguments/arguments.py b/prowler/providers/microsoft365/lib/arguments/arguments.py deleted file mode 100644 index d3e38642e7..0000000000 --- a/prowler/providers/microsoft365/lib/arguments/arguments.py +++ /dev/null @@ -1,48 +0,0 @@ -def init_parser(self): - """Init the Microsoft365 Provider CLI parser""" - microsoft365_parser = self.subparsers.add_parser( - "microsoft365", - parents=[self.common_providers_parser], - help="Microsoft365 Provider", - ) - # Authentication Modes - microsoft365_auth_subparser = microsoft365_parser.add_argument_group( - "Authentication Modes" - ) - microsoft365_auth_modes_group = ( - microsoft365_auth_subparser.add_mutually_exclusive_group() - ) - microsoft365_auth_modes_group.add_argument( - "--az-cli-auth", - action="store_true", - help="Use Azure CLI authentication to log in against Microsoft365", - ) - microsoft365_auth_modes_group.add_argument( - "--sp-env-auth", - action="store_true", - help="Use Azure Service Principal environment variables authentication to log in against Microsoft365", - ) - microsoft365_auth_modes_group.add_argument( - "--browser-auth", - action="store_true", - help="Use Azure interactive browser authentication to log in against Microsoft365", - ) - microsoft365_parser.add_argument( - "--tenant-id", - nargs="?", - default=None, - help="Microsoft365 Tenant ID to be used with --browser-auth option", - ) - # Regions - microsoft365_regions_subparser = microsoft365_parser.add_argument_group("Regions") - microsoft365_regions_subparser.add_argument( - "--region", - nargs="?", - default="Microsoft365Global", - choices=[ - "Microsoft365Global", - "Microsoft365GlobalChina", - "Microsoft365USGovernment", - ], - help="Microsoft365 region to be used, default is Microsoft365Global", - ) diff --git a/prowler/providers/microsoft365/lib/service/service.py b/prowler/providers/microsoft365/lib/service/service.py deleted file mode 100644 index 85f54b260e..0000000000 --- a/prowler/providers/microsoft365/lib/service/service.py +++ /dev/null @@ -1,14 +0,0 @@ -from msgraph import GraphServiceClient - -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider - - -class Microsoft365Service: - def __init__( - self, - provider: Microsoft365Provider, - ): - self.client = GraphServiceClient(credentials=provider.session) - - self.audit_config = provider.audit_config - self.fixer_config = provider.fixer_config diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml index 2dc9bef561..e9a4e6fad2 100644 --- a/tests/config/fixtures/config.yaml +++ b/tests/config/fixtures/config.yaml @@ -431,8 +431,8 @@ kubernetes: "TLS_RSA_WITH_AES_128_GCM_SHA256", ] -# Microsoft365 Configuration -microsoft365: +# M365 Configuration +m365: # Conditional Access Policy # policy.session_controls.sign_in_frequency.frequency in hours sign_in_frequency: 4 diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index 37bec15d94..a8f256ef36 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -1,3 +1,4 @@ +import sys import uuid from argparse import ArgumentTypeError @@ -16,11 +17,13 @@ prowler_command = "prowler" # capsys # https://docs.pytest.org/en/7.1.x/how-to/capture-stdout-stderr.html -prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,microsoft365,nhn,dashboard} ..." +prowler_default_usage_error = ( + "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,nhn,dashboard} ..." +) def mock_get_available_providers(): - return ["aws", "azure", "gcp", "kubernetes", "microsoft365", "nhn"] + return ["aws", "azure", "gcp", "kubernetes", "m365", "nhn"] @pytest.mark.arg_parser @@ -1363,3 +1366,13 @@ class Test_Parser: valid_role_names = ["prowler-role" "test@" "test=test+test,."] for role_name in valid_role_names: assert validate_role_session_name(role_name) == role_name + + def test_microsoft365_alias_conversion(self): + original_argv = sys.argv.copy() + try: + sys.argv = ["prowler", "microsoft365"] + parser = ProwlerArgumentParser() + args = parser.parse() + assert args.provider == "m365" + finally: + sys.argv = original_argv diff --git a/tests/lib/outputs/finding_test.py b/tests/lib/outputs/finding_test.py index 05270785cd..3dea2f614b 100644 --- a/tests/lib/outputs/finding_test.py +++ b/tests/lib/outputs/finding_test.py @@ -956,9 +956,9 @@ class TestFinding: "prowler.lib.outputs.finding.get_check_compliance", new=mock_get_check_compliance, ) - def test_transform_api_finding_microsoft365(self): + def test_transform_api_finding_m365(self): provider = MagicMock() - provider.type = "microsoft365" + provider.type = "m365" provider.identity.identity_type = "ms_identity_type" provider.identity.identity_id = "ms_identity_id" provider.identity.tenant_id = "ms-tenant-id" @@ -970,7 +970,7 @@ class TestFinding: dummy_finding.status = "PASS" dummy_finding.status_extended = "M365 check extended" check_metadata = { - "provider": "microsoft365", + "provider": "m365", "checkid": "m365-check-001", "checktitle": "Test M365 Check", "checktype": [], diff --git a/tests/lib/powershell/powershell_test.py b/tests/lib/powershell/powershell_test.py new file mode 100644 index 0000000000..6dab9349a0 --- /dev/null +++ b/tests/lib/powershell/powershell_test.py @@ -0,0 +1,125 @@ +from unittest.mock import MagicMock, patch + +from prowler.providers.m365.lib.powershell.m365_powershell import PowerShellSession + + +class TestPowerShellSession: + @patch("subprocess.Popen") + def test_init(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + mock_popen.assert_called_once() + assert session.process == mock_process + assert session.END == "" + session.close() + + @patch("subprocess.Popen") + def test_sanitize(self, _): + session = PowerShellSession() + + test_cases = [ + ("test@example.com", "test@example.com"), + ("test@example.com!", "test@example.com"), + ("test@example.com#", "test@example.com"), + ("test@example.com$", "test@example.com"), + ("test@example.com%", "test@example.com"), + ("test@example.com^", "test@example.com"), + ("test@example.com&", "test@example.com"), + ("test@example.com*", "test@example.com"), + ("test@example.com(", "test@example.com"), + ("test@example.com)", "test@example.com"), + ("test@example.com-", "test@example.com-"), + ("test@example.com_", "test@example.com_"), + ("test@example.com+", "test@example.com+"), + ("test_;echo pwned;password", "test_echopwnedpassword"), + ] + + for input_str, expected in test_cases: + assert session.sanitize(input_str) == expected + session.close() + + @patch("subprocess.Popen") + def test_remove_ansi(self, mock_popen): + session = PowerShellSession() + + test_cases = [ + ("\x1b[32mSuccess\x1b[0m", "Success"), + ("\x1b[31mError\x1b[0m", "Error"), + ("\x1b[33mWarning\x1b[0m", "Warning"), + ("Normal text", "Normal text"), + ("\x1b[1mBold\x1b[0m", "Bold"), + ] + + for input_str, expected in test_cases: + assert session.remove_ansi(input_str) == expected + session.close() + + @patch("subprocess.Popen") + def test_execute(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + command = "Get-Command" + expected_output = '{"Name": "Get-Command"}' + + with patch.object(session, "read_output", return_value=expected_output): + result = session.execute(command) + + mock_process.stdin.write.assert_any_call(f"{command}\n") + mock_process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") + assert result == {"Name": "Get-Command"} + session.close() + + @patch("subprocess.Popen") + def test_read_output(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + # Test normal output + with patch.object(session, "read_output", return_value="test@example.com"): + assert session.read_output() == "test@example.com" + + # Test timeout + mock_process.stdout.readline.return_value = "test output\n" + with patch.object(session, "remove_ansi", return_value="test output"): + assert session.read_output(timeout=0.1, default="") == "" + session.close() + + @patch("subprocess.Popen") + def test_json_parse_output(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + test_cases = [ + ('{"key": "value"}', {"key": "value"}), + ('[{"key": "value"}]', [{"key": "value"}]), + ( + '[{"key": "value"},{"key": "value"}]', + [{"key": "value"}, {"key": "value"}], + ), + ("[{}]", [{}]), + ("[{},{}]", [{}, {}]), + ("not json", {}), + ("", {}), + ] + + for input_str, expected in test_cases: + result = session.json_parse_output(input_str) + assert result == expected + session.close() + + @patch("subprocess.Popen") + def test_close(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + session.close() + + mock_process.stdin.flush.assert_called_once() + mock_process.terminate.assert_called_once() + mock_process = None diff --git a/tests/providers/microsoft365/lib/mutelist/fixtures/microsoft365_mutelist.yaml b/tests/providers/m365/lib/mutelist/fixtures/m365_mutelist.yaml similarity index 100% rename from tests/providers/microsoft365/lib/mutelist/fixtures/microsoft365_mutelist.yaml rename to tests/providers/m365/lib/mutelist/fixtures/m365_mutelist.yaml diff --git a/tests/providers/microsoft365/lib/mutelist/microsoft365_mutelist_test.py b/tests/providers/m365/lib/mutelist/m365_mutelist_test.py similarity index 82% rename from tests/providers/microsoft365/lib/mutelist/microsoft365_mutelist_test.py rename to tests/providers/m365/lib/mutelist/m365_mutelist_test.py index 5bbde2e89d..8df9a97292 100644 --- a/tests/providers/microsoft365/lib/mutelist/microsoft365_mutelist_test.py +++ b/tests/providers/m365/lib/mutelist/m365_mutelist_test.py @@ -1,17 +1,15 @@ import yaml from mock import MagicMock -from prowler.providers.microsoft365.lib.mutelist.mutelist import Microsoft365Mutelist +from prowler.providers.m365.lib.mutelist.mutelist import M365Mutelist from tests.lib.outputs.fixtures.fixtures import generate_finding_output -MUTELIST_FIXTURE_PATH = ( - "tests/providers/microsoft365/lib/mutelist/fixtures/microsoft365_mutelist.yaml" -) +MUTELIST_FIXTURE_PATH = "tests/providers/m365/lib/mutelist/fixtures/m365_mutelist.yaml" -class TestMicrosoft365Mutelist: +class TestM365Mutelist: def test_get_mutelist_file_from_local_file(self): - mutelist = Microsoft365Mutelist(mutelist_path=MUTELIST_FIXTURE_PATH) + mutelist = M365Mutelist(mutelist_path=MUTELIST_FIXTURE_PATH) with open(MUTELIST_FIXTURE_PATH) as f: mutelist_fixture = yaml.safe_load(f)["Mutelist"] @@ -21,7 +19,7 @@ class TestMicrosoft365Mutelist: def test_get_mutelist_file_from_local_file_non_existent(self): mutelist_path = "tests/lib/mutelist/fixtures/not_present" - mutelist = Microsoft365Mutelist(mutelist_path=mutelist_path) + mutelist = M365Mutelist(mutelist_path=mutelist_path) assert mutelist.mutelist == {} assert mutelist.mutelist_file_path == mutelist_path @@ -34,7 +32,7 @@ class TestMicrosoft365Mutelist: mutelist_fixture["Accounts1"] = mutelist_fixture["Accounts"] del mutelist_fixture["Accounts"] - mutelist = Microsoft365Mutelist(mutelist_content=mutelist_fixture) + mutelist = M365Mutelist(mutelist_content=mutelist_fixture) assert not mutelist.validate_mutelist() assert mutelist.mutelist == {} @@ -55,7 +53,7 @@ class TestMicrosoft365Mutelist: } } - mutelist = Microsoft365Mutelist(mutelist_content=mutelist_content) + mutelist = M365Mutelist(mutelist_content=mutelist_content) finding = MagicMock finding.tenant_id = "subscription_1" @@ -84,7 +82,7 @@ class TestMicrosoft365Mutelist: } } - mutelist = Microsoft365Mutelist(mutelist_content=mutelist_content) + mutelist = M365Mutelist(mutelist_content=mutelist_content) finding_1 = generate_finding_output( check_id="check_test", diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py new file mode 100644 index 0000000000..f32cc1c780 --- /dev/null +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -0,0 +1,210 @@ +from unittest.mock import MagicMock, patch + +from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell +from prowler.providers.m365.models import M365Credentials + + +class Testm365PowerShell: + @patch("subprocess.Popen") + def test_init(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + + with patch.object(M365PowerShell, "init_credential") as mock_init_credential: + session = M365PowerShell(credentials) + + mock_popen.assert_called_once() + mock_init_credential.assert_called_once_with(credentials) + assert session.process == mock_process + assert session.END == "" + session.close() + + @patch("subprocess.Popen") + def test_sanitize(self, _): + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + test_cases = [ + ("test@example.com", "test@example.com"), + ("test@example.com!", "test@example.com"), + ("test@example.com#", "test@example.com"), + ("test@example.com$", "test@example.com"), + ("test@example.com%", "test@example.com"), + ("test@example.com^", "test@example.com"), + ("test@example.com&", "test@example.com"), + ("test@example.com*", "test@example.com"), + ("test@example.com(", "test@example.com"), + ("test@example.com)", "test@example.com"), + ("test@example.com-", "test@example.com-"), + ("test@example.com_", "test@example.com_"), + ("test@example.com+", "test@example.com+"), + ("test_;echo pwned;password", "test_echopwnedpassword"), + ] + + for input_str, expected in test_cases: + assert session.sanitize(input_str) == expected + session.close() + + @patch("subprocess.Popen") + def test_init_credential(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials( + user="test@example.com", + passwd="test_password", + client_id="test_client_id", + client_secret="test_client_secret", + tenant_id="test_tenant_id", + ) + session = M365PowerShell(credentials) + + session.execute = MagicMock() + + session.init_credential(credentials) + + session.execute.assert_any_call(f'$user = "{credentials.user}"') + session.execute.assert_any_call( + f'$secureString = "{credentials.passwd}" | ConvertTo-SecureString' + ) + session.execute.assert_any_call( + "$credential = New-Object System.Management.Automation.PSCredential ($user, $secureString)" + ) + session.close() + + @patch("subprocess.Popen") + @patch("msal.ConfidentialClientApplication") + def test_test_credentials(self, mock_msal, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + mock_msal_instance = MagicMock() + mock_msal.return_value = mock_msal_instance + mock_msal_instance.acquire_token_by_username_password.return_value = { + "access_token": "test_token" + } + + credentials = M365Credentials( + user="test@example.com", + passwd="test_password", + client_id="test_client_id", + client_secret="test_client_secret", + tenant_id="test_tenant_id", + ) + session = M365PowerShell(credentials) + + session.execute = MagicMock() + session.process.stdin.write = MagicMock() + session.read_output = MagicMock(return_value="decrypted_password") + + assert session.test_credentials(credentials) is True + + session.execute.assert_any_call( + f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString\n' + ) + session.execute.assert_any_call( + f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' + ) + session.process.stdin.write.assert_any_call( + 'Write-Output "$($credential.GetNetworkCredential().Password)"\n' + ) + session.process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") + + mock_msal.assert_called_once_with( + client_id="test_client_id", + client_credential="test_client_secret", + authority="https://login.microsoftonline.com/test_tenant_id", + ) + mock_msal_instance.acquire_token_by_username_password.assert_called_once_with( + username="test@example.com", + password="decrypted_password", + scopes=["https://graph.microsoft.com/.default"], + ) + session.close() + + @patch("subprocess.Popen") + def test_remove_ansi(self, mock_popen): + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + test_cases = [ + ("\x1b[32mSuccess\x1b[0m", "Success"), + ("\x1b[31mError\x1b[0m", "Error"), + ("\x1b[33mWarning\x1b[0m", "Warning"), + ("Normal text", "Normal text"), + ("\x1b[1mBold\x1b[0m", "Bold"), + ] + + for input_str, expected in test_cases: + assert session.remove_ansi(input_str) == expected + session.close() + + @patch("subprocess.Popen") + def test_execute(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + command = "Get-Command" + expected_output = '{"Name": "Get-Command"}' + + with patch.object(session, "read_output", return_value=expected_output): + result = session.execute(command) + + mock_process.stdin.write.assert_any_call(f"{command}\n") + mock_process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") + assert result == {"Name": "Get-Command"} + session.close() + + @patch("subprocess.Popen") + def test_read_output(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + # Test normal output + with patch.object(session, "read_output", return_value="test@example.com"): + assert session.read_output() == "test@example.com" + + # Test timeout + mock_process.stdout.readline.return_value = "test output\n" + with patch.object(session, "remove_ansi", return_value="test output"): + assert session.read_output(timeout=0.1, default="") == "" + session.close() + + @patch("subprocess.Popen") + def test_json_parse_output(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + test_cases = [ + ('{"key": "value"}', {"key": "value"}), + ('[{"key": "value"}]', [{"key": "value"}]), + ( + '[{"key": "value"},{"key": "value"}]', + [{"key": "value"}, {"key": "value"}], + ), + ("[{}]", [{}]), + ("[{},{}]", [{}, {}]), + ("not json", {}), + ("", {}), + ] + + for input_str, expected in test_cases: + result = session.json_parse_output(input_str) + assert result == expected + session.close() + + @patch("subprocess.Popen") + def test_close(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + session.close() + + mock_process.stdin.flush.assert_called_once() + mock_process.terminate.assert_called_once() diff --git a/tests/providers/microsoft365/lib/regions/microsoft365_regions_test.py b/tests/providers/m365/lib/regions/m365_regions_test.py similarity index 76% rename from tests/providers/microsoft365/lib/regions/microsoft365_regions_test.py rename to tests/providers/m365/lib/regions/m365_regions_test.py index 49ec5a480d..676e769276 100644 --- a/tests/providers/microsoft365/lib/regions/microsoft365_regions_test.py +++ b/tests/providers/m365/lib/regions/m365_regions_test.py @@ -1,6 +1,6 @@ from azure.identity import AzureAuthorityHosts -from prowler.providers.microsoft365.lib.regions.regions import ( +from prowler.providers.m365.lib.regions.regions import ( MICROSOFT365_CHINA_CLOUD, MICROSOFT365_GENERIC_CLOUD, MICROSOFT365_US_GOV_CLOUD, @@ -8,25 +8,25 @@ from prowler.providers.microsoft365.lib.regions.regions import ( ) -class Test_microsoft365_regions: +class Test_m365_regions: def test_get_regions_config(self): allowed_regions = [ - "Microsoft365Global", - "Microsoft365China", - "Microsoft365USGovernment", + "M365Global", + "M365China", + "M365USGovernment", ] expected_output = { - "Microsoft365Global": { + "M365Global": { "authority": None, "base_url": MICROSOFT365_GENERIC_CLOUD, "credential_scopes": [MICROSOFT365_GENERIC_CLOUD + "/.default"], }, - "Microsoft365China": { + "M365China": { "authority": AzureAuthorityHosts.AZURE_CHINA, "base_url": MICROSOFT365_CHINA_CLOUD, "credential_scopes": [MICROSOFT365_CHINA_CLOUD + "/.default"], }, - "Microsoft365USGovernment": { + "M365USGovernment": { "authority": AzureAuthorityHosts.AZURE_GOVERNMENT, "base_url": MICROSOFT365_US_GOV_CLOUD, "credential_scopes": [MICROSOFT365_US_GOV_CLOUD + "/.default"], diff --git a/tests/providers/microsoft365/microsoft365_fixtures.py b/tests/providers/m365/m365_fixtures.py similarity index 53% rename from tests/providers/microsoft365/microsoft365_fixtures.py rename to tests/providers/m365/m365_fixtures.py index 1dbb09c612..0eb3c203e1 100644 --- a/tests/providers/microsoft365/microsoft365_fixtures.py +++ b/tests/providers/m365/m365_fixtures.py @@ -1,10 +1,11 @@ from azure.identity import DefaultAzureCredential from mock import MagicMock -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider -from prowler.providers.microsoft365.models import ( - Microsoft365IdentityInfo, - Microsoft365RegionConfig, +from prowler.providers.m365.m365_provider import M365Provider +from prowler.providers.m365.models import ( + M365Credentials, + M365IdentityInfo, + M365RegionConfig, ) # Azure Identity @@ -18,20 +19,24 @@ LOCATION = "global" # Mocked Azure Audit Info -def set_mocked_microsoft365_provider( - credentials: DefaultAzureCredential = DefaultAzureCredential(), - identity: Microsoft365IdentityInfo = Microsoft365IdentityInfo( +def set_mocked_m365_provider( + session_credentials: DefaultAzureCredential = DefaultAzureCredential(), + credentials: M365Credentials = M365Credentials( + user="user@email.com", passwd="111111aa111111aaa1111" + ), + identity: M365IdentityInfo = M365IdentityInfo( identity_id=IDENTITY_ID, identity_type=IDENTITY_TYPE, tenant_id=TENANT_ID, tenant_domain=DOMAIN, ), audit_config: dict = None, - azure_region_config: Microsoft365RegionConfig = Microsoft365RegionConfig(), -) -> Microsoft365Provider: + azure_region_config: M365RegionConfig = M365RegionConfig(), +) -> M365Provider: provider = MagicMock() - provider.type = "microsoft365" - provider.session.credentials = credentials + provider.type = "m365" + provider.session.credentials = session_credentials + provider.credentials = credentials provider.identity = identity provider.audit_config = audit_config provider.region_config = azure_region_config diff --git a/tests/providers/m365/m365_provider_test.py b/tests/providers/m365/m365_provider_test.py new file mode 100644 index 0000000000..22f0bef4b0 --- /dev/null +++ b/tests/providers/m365/m365_provider_test.py @@ -0,0 +1,452 @@ +from unittest.mock import patch +from uuid import uuid4 + +import pytest +from azure.core.credentials import AccessToken +from azure.identity import ( + ClientSecretCredential, + DefaultAzureCredential, + InteractiveBrowserCredential, +) +from mock import MagicMock + +from prowler.config.config import ( + default_config_file_path, + default_fixer_config_file_path, + load_and_validate_config_file, +) +from prowler.providers.common.models import Connection +from prowler.providers.m365.exceptions.exceptions import ( + M365HTTPResponseError, + M365MissingEnvironmentUserCredentialsError, + M365NoAuthenticationMethodError, +) +from prowler.providers.m365.m365_provider import M365Provider +from prowler.providers.m365.models import ( + M365Credentials, + M365IdentityInfo, + M365RegionConfig, +) +from tests.providers.m365.m365_fixtures import ( + CLIENT_ID, + CLIENT_SECRET, + DOMAIN, + IDENTITY_ID, + IDENTITY_TYPE, + LOCATION, + TENANT_ID, +) + + +class TestM365Provider: + def test_m365_provider(self): + tenant_id = None + client_id = None + client_secret = None + + fixer_config = load_and_validate_config_file( + "m365", default_fixer_config_file_path + ) + azure_region = "M365Global" + + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session", + return_value=ClientSecretCredential( + client_id=CLIENT_ID, + tenant_id=TENANT_ID, + client_secret=CLIENT_SECRET, + ), + ), + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_identity", + return_value=M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type=IDENTITY_TYPE, + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ), + ), + ): + m365_provider = M365Provider( + sp_env_auth=True, + az_cli_auth=False, + browser_auth=False, + env_auth=False, + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + region=azure_region, + config_path=default_config_file_path, + fixer_config=fixer_config, + ) + + assert m365_provider.region_config == M365RegionConfig( + name="M365Global", + authority=None, + base_url="https://graph.microsoft.com", + credential_scopes=["https://graph.microsoft.com/.default"], + ) + assert m365_provider.identity == M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type=IDENTITY_TYPE, + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ) + + def test_m365_provider_env_auth(self): + tenant_id = None + client_id = None + client_secret = None + + fixer_config = load_and_validate_config_file( + "m365", default_fixer_config_file_path + ) + azure_region = "M365Global" + + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session", + return_value=ClientSecretCredential( + client_id=CLIENT_ID, + tenant_id=TENANT_ID, + client_secret=CLIENT_SECRET, + ), + ), + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_identity", + return_value=M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type=IDENTITY_TYPE, + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ), + ), + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_powershell", + return_value=M365Credentials( + user="test@test.com", + passwd="password", + ), + ), + ): + m365_provider = M365Provider( + sp_env_auth=False, + az_cli_auth=False, + browser_auth=False, + env_auth=True, + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + region=azure_region, + config_path=default_config_file_path, + fixer_config=fixer_config, + ) + + assert m365_provider.region_config == M365RegionConfig( + name="M365Global", + authority=None, + base_url="https://graph.microsoft.com", + credential_scopes=["https://graph.microsoft.com/.default"], + ) + assert m365_provider.identity == M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type=IDENTITY_TYPE, + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ) + + def test_m365_provider_cli_auth(self): + """Test M365 Provider initialization with CLI authentication""" + azure_region = "M365Global" + fixer_config = load_and_validate_config_file( + "m365", default_fixer_config_file_path + ) + + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session", + return_value=DefaultAzureCredential( + exclude_environment_credential=True, + exclude_cli_credential=False, + exclude_managed_identity_credential=True, + exclude_visual_studio_code_credential=True, + exclude_shared_token_cache_credential=True, + exclude_powershell_credential=True, + exclude_browser_credential=True, + ), + ), + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_identity", + return_value=M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type="User", + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ), + ), + ): + m365_provider = M365Provider( + sp_env_auth=False, + az_cli_auth=True, + browser_auth=False, + env_auth=False, + region=azure_region, + config_path=default_config_file_path, + fixer_config=fixer_config, + ) + + assert m365_provider.region_config == M365RegionConfig( + name="M365Global", + authority=None, + base_url="https://graph.microsoft.com", + credential_scopes=["https://graph.microsoft.com/.default"], + ) + assert m365_provider.identity == M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type="User", + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ) + assert isinstance(m365_provider.session, DefaultAzureCredential) + + def test_m365_provider_browser_auth(self): + """Test M365 Provider initialization with Browser authentication""" + azure_region = "M365Global" + fixer_config = load_and_validate_config_file( + "m365", default_fixer_config_file_path + ) + + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session", + return_value=InteractiveBrowserCredential( + tenant_id=TENANT_ID, + ), + ), + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_identity", + return_value=M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type="User", + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ), + ), + ): + m365_provider = M365Provider( + sp_env_auth=False, + az_cli_auth=False, + browser_auth=True, + env_auth=False, + tenant_id=TENANT_ID, + region=azure_region, + config_path=default_config_file_path, + fixer_config=fixer_config, + ) + + assert m365_provider.region_config == M365RegionConfig( + name="M365Global", + authority=None, + base_url="https://graph.microsoft.com", + credential_scopes=["https://graph.microsoft.com/.default"], + ) + assert m365_provider.identity == M365IdentityInfo( + identity_id=IDENTITY_ID, + identity_type="User", + tenant_id=TENANT_ID, + tenant_domain=DOMAIN, + location=LOCATION, + ) + assert isinstance(m365_provider.session, InteractiveBrowserCredential) + + def test_test_connection_browser_auth(self): + with ( + patch( + "prowler.providers.m365.m365_provider.DefaultAzureCredential" + ) as mock_default_credential, + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session, + patch( + "prowler.providers.m365.m365_provider.GraphServiceClient" + ) as mock_graph_client, + ): + # Mock the return value of DefaultAzureCredential + mock_credentials = MagicMock() + mock_credentials.get_token.return_value = AccessToken( + token="fake_token", expires_on=9999999999 + ) + mock_default_credential.return_value = mock_credentials + + # Mock setup_session to return a mocked session object + mock_session = MagicMock() + mock_setup_session.return_value = mock_session + + # Mock GraphServiceClient to avoid real API calls + mock_client = MagicMock() + mock_graph_client.return_value = mock_client + + test_connection = M365Provider.test_connection( + browser_auth=True, + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=False, + ) + + assert isinstance(test_connection, Connection) + assert test_connection.is_connected + assert test_connection.error is None + + def test_test_connection_tenant_id_client_id_client_secret(self): + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session, + patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials, + ): + # Mock setup_session to return a mocked session object + mock_session = MagicMock() + mock_setup_session.return_value = mock_session + + # Mock ValidateStaticCredentials to avoid real API calls + mock_validate_static_credentials.return_value = None + + test_connection = M365Provider.test_connection( + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=False, + client_id=str(uuid4()), + client_secret=str(uuid4()), + ) + + assert isinstance(test_connection, Connection) + assert test_connection.is_connected + assert test_connection.error is None + + def test_test_connection_tenant_id_client_id_client_secret_user_encrypted_password( + self, + ): + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session, + patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials, + ): + # Mock setup_session to return a mocked session object + mock_session = MagicMock() + mock_setup_session.return_value = mock_session + + # Mock ValidateStaticCredentials to avoid real API calls + mock_validate_static_credentials.return_value = None + + test_connection = M365Provider.test_connection( + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=False, + client_id=str(uuid4()), + client_secret=str(uuid4()), + user="user@user.com", + encrypted_password="AAAA1111", + ) + + assert isinstance(test_connection, Connection) + assert test_connection.is_connected + assert test_connection.error is None + + def test_test_connection_with_httpresponseerror(self): + with patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session: + mock_setup_session.side_effect = M365HTTPResponseError( + file="test_file", original_exception="Simulated HttpResponseError" + ) + + with pytest.raises(M365HTTPResponseError) as exception: + M365Provider.test_connection( + az_cli_auth=True, + raise_on_exception=True, + ) + + assert exception.type == M365HTTPResponseError + assert ( + exception.value.args[0] + == "[6003] Error in HTTP response from Microsoft 365 - Simulated HttpResponseError" + ) + + def test_test_connection_with_exception(self): + with patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session: + mock_setup_session.side_effect = Exception("Simulated Exception") + + with pytest.raises(Exception) as exception: + M365Provider.test_connection( + sp_env_auth=True, + raise_on_exception=True, + ) + + assert exception.type is Exception + assert exception.value.args[0] == "Simulated Exception" + + def test_test_connection_without_any_method(self): + with pytest.raises(M365NoAuthenticationMethodError) as exception: + M365Provider.test_connection() + + assert exception.type == M365NoAuthenticationMethodError + assert ( + "M365 provider requires at least one authentication method set: [--env-auth | --az-cli-auth | --sp-env-auth | --browser-auth]" + in exception.value.args[0] + ) + + def test_setup_powershell_valid_credentials(self): + credentials_dict = { + "user": "test@example.com", + "encrypted_password": "test_password", + "client_id": "test_client_id", + "tenant_id": "test_tenant_id", + "client_secret": "test_client_secret", + } + + with patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", + return_value=True, + ): + result = M365Provider.setup_powershell( + env_auth=False, m365_credentials=credentials_dict + ) + + assert result.user == credentials_dict["user"] + assert result.passwd == credentials_dict["encrypted_password"] + + def test_setup_powershell_invalid_env_credentials(self): + credentials = None + + with patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell" + ) as mock_powershell: + mock_session = MagicMock() + mock_session.test_credentials.return_value = False + mock_powershell.return_value = mock_session + + with pytest.raises(M365MissingEnvironmentUserCredentialsError) as exc_info: + M365Provider.setup_powershell( + env_auth=True, m365_credentials=credentials + ) + + assert ( + "Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication" + in str(exc_info.value) + ) + mock_session.test_credentials.assert_not_called() diff --git a/tests/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py b/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py similarity index 68% rename from tests/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py rename to tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py index 4f7c5c2bc0..9e8ccfbc7d 100644 --- a/tests/providers/microsoft365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py @@ -1,10 +1,7 @@ from unittest import mock from uuid import uuid4 -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_admincenter_groups_not_public_visibility: @@ -16,14 +13,14 @@ class Test_admincenter_groups_not_public_visibility: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( + from prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( admincenter_groups_not_public_visibility, ) @@ -41,17 +38,17 @@ class Test_admincenter_groups_not_public_visibility: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( + from prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( admincenter_groups_not_public_visibility, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( Group, ) @@ -79,17 +76,17 @@ class Test_admincenter_groups_not_public_visibility: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( + from prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility import ( admincenter_groups_not_public_visibility, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( Group, ) diff --git a/tests/providers/microsoft365/services/admincenter/admincenter_service_test.py b/tests/providers/m365/services/admincenter/admincenter_service_test.py similarity index 65% rename from tests/providers/microsoft365/services/admincenter/admincenter_service_test.py rename to tests/providers/m365/services/admincenter/admincenter_service_test.py index 1aaf11f8f4..f72c14ce71 100644 --- a/tests/providers/microsoft365/services/admincenter/admincenter_service_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_service_test.py @@ -1,16 +1,13 @@ from unittest.mock import patch -from prowler.providers.microsoft365.models import Microsoft365IdentityInfo -from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.admincenter.admincenter_service import ( AdminCenter, DirectoryRole, Group, User, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider async def mock_admincenter_get_users(_): @@ -40,41 +37,39 @@ async def mock_admincenter_get_groups(_): @patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_service.AdminCenter._get_users", + "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_users", new=mock_admincenter_get_users, ) @patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_service.AdminCenter._get_directory_roles", + "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_directory_roles", new=mock_admincenter_get_directory_roles, ) @patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_service.AdminCenter._get_groups", + "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_groups", new=mock_admincenter_get_groups, ) class Test_AdminCenter_Service: def test_get_client(self): admincenter_client = AdminCenter( - set_mocked_microsoft365_provider( - identity=Microsoft365IdentityInfo(tenant_domain=DOMAIN) - ) + set_mocked_m365_provider(identity=M365IdentityInfo(tenant_domain=DOMAIN)) ) assert admincenter_client.client.__class__.__name__ == "GraphServiceClient" def test_get_users(self): - admincenter_client = AdminCenter(set_mocked_microsoft365_provider()) + admincenter_client = AdminCenter(set_mocked_m365_provider()) assert len(admincenter_client.users) == 1 assert admincenter_client.users["user-1@tenant1.es"].id == "id-1" assert admincenter_client.users["user-1@tenant1.es"].name == "User 1" def test_get_group_settings(self): - admincenter_client = AdminCenter(set_mocked_microsoft365_provider()) + admincenter_client = AdminCenter(set_mocked_m365_provider()) assert len(admincenter_client.groups) == 1 assert admincenter_client.groups["id-1"].id == "id-1" assert admincenter_client.groups["id-1"].name == "Test" assert admincenter_client.groups["id-1"].visibility == "Public" def test_get_directory_roles(self): - admincenter_client = AdminCenter(set_mocked_microsoft365_provider()) + admincenter_client = AdminCenter(set_mocked_m365_provider()) assert ( admincenter_client.directory_roles["GlobalAdministrator"].id == "id-directory-role" diff --git a/tests/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py b/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py similarity index 69% rename from tests/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py rename to tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py index 15630b90c6..7c7cb7506b 100644 --- a/tests/providers/microsoft365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py @@ -1,10 +1,7 @@ from unittest import mock from uuid import uuid4 -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_admincenter_settings_password_never_expire: @@ -16,14 +13,14 @@ class Test_admincenter_settings_password_never_expire: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( + from prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( admincenter_settings_password_never_expire, ) @@ -41,17 +38,17 @@ class Test_admincenter_settings_password_never_expire: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( Domain, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( + from prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( admincenter_settings_password_never_expire, ) @@ -82,17 +79,17 @@ class Test_admincenter_settings_password_never_expire: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( Domain, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( + from prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire import ( admincenter_settings_password_never_expire, ) diff --git a/tests/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py b/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py similarity index 70% rename from tests/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py rename to tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py index f684c11988..06f807c1c2 100644 --- a/tests/providers/microsoft365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py @@ -1,10 +1,7 @@ from unittest import mock from uuid import uuid4 -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_admincenter_users_admins_reduced_license_footprint: @@ -16,14 +13,14 @@ class Test_admincenter_users_admins_reduced_license_footprint: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( + from prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( admincenter_users_admins_reduced_license_footprint, ) @@ -41,17 +38,17 @@ class Test_admincenter_users_admins_reduced_license_footprint: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( + from prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( admincenter_users_admins_reduced_license_footprint, ) @@ -78,17 +75,17 @@ class Test_admincenter_users_admins_reduced_license_footprint: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( + from prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( admincenter_users_admins_reduced_license_footprint, ) @@ -124,17 +121,17 @@ class Test_admincenter_users_admins_reduced_license_footprint: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( + from prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( admincenter_users_admins_reduced_license_footprint, ) @@ -170,17 +167,17 @@ class Test_admincenter_users_admins_reduced_license_footprint: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( + from prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import ( admincenter_users_admins_reduced_license_footprint, ) diff --git a/tests/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py b/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py similarity index 74% rename from tests/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py rename to tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py index b7fafb56a9..994dbbcf49 100644 --- a/tests/providers/microsoft365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py @@ -1,10 +1,7 @@ from unittest import mock from uuid import uuid4 -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_admincenter_users_between_two_and_four_global_admins: @@ -16,14 +13,14 @@ class Test_admincenter_users_between_two_and_four_global_admins: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( + from prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( admincenter_users_between_two_and_four_global_admins, ) @@ -41,18 +38,18 @@ class Test_admincenter_users_between_two_and_four_global_admins: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( DirectoryRole, User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( + from prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( admincenter_users_between_two_and_four_global_admins, ) @@ -92,18 +89,18 @@ class Test_admincenter_users_between_two_and_four_global_admins: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( DirectoryRole, User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( + from prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( admincenter_users_between_two_and_four_global_admins, ) @@ -154,18 +151,18 @@ class Test_admincenter_users_between_two_and_four_global_admins: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", + "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, ), ): - from prowler.providers.microsoft365.services.admincenter.admincenter_service import ( + from prowler.providers.m365.services.admincenter.admincenter_service import ( DirectoryRole, User, ) - from prowler.providers.microsoft365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( + from prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins import ( admincenter_users_between_two_and_four_global_admins, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py b/tests/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py similarity index 76% rename from tests/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py rename to tests/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py index 9a72389813..8599a5d56a 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_admin_consent_workflow_enabled/entra_admin_consent_workflow_enabled_test.py @@ -1,12 +1,7 @@ from unittest import mock -from prowler.providers.microsoft365.services.entra.entra_service import ( - AdminConsentPolicy, -) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from prowler.providers.m365.services.entra.entra_service import AdminConsentPolicy +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_admin_consent_workflow_enabled: @@ -20,14 +15,14 @@ class Test_entra_admin_consent_workflow_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( entra_admin_consent_workflow_enabled, ) @@ -62,14 +57,14 @@ class Test_entra_admin_consent_workflow_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( entra_admin_consent_workflow_enabled, ) @@ -104,14 +99,14 @@ class Test_entra_admin_consent_workflow_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( entra_admin_consent_workflow_enabled, ) @@ -148,14 +143,14 @@ class Test_entra_admin_consent_workflow_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_consent_workflow_enabled.entra_admin_consent_workflow_enabled import ( entra_admin_consent_workflow_enabled, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py b/tests/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py similarity index 84% rename from tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py rename to tests/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py index 23bed663b9..1226f07261 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py +++ b/tests/providers/m365/services/entra/entra_admin_portals_access_restriction/entra_admin_portals_access_restriction_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -14,10 +14,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_admin_portals_access_restriction: @@ -28,14 +25,14 @@ class Test_entra_admin_portals_access_restriction: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", + "prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + from prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( entra_admin_portals_access_restriction, ) @@ -63,17 +60,17 @@ class Test_entra_admin_portals_access_restriction: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", + "prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + from prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( entra_admin_portals_access_restriction, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -137,17 +134,17 @@ class Test_entra_admin_portals_access_restriction: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", + "prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + from prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( entra_admin_portals_access_restriction, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -215,17 +212,17 @@ class Test_entra_admin_portals_access_restriction: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", + "prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( + from prowler.providers.m365.services.entra.entra_admin_portals_access_restriction.entra_admin_portals_access_restriction import ( entra_admin_portals_access_restriction, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py b/tests/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py similarity index 82% rename from tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py rename to tests/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py index 4e718d29f7..3eae3c9517 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py +++ b/tests/providers/m365/services/entra/entra_admin_users_cloud_only/entra_admin_users_cloud_only_test.py @@ -1,9 +1,7 @@ from unittest import mock -from prowler.providers.microsoft365.services.entra.entra_service import AdminRoles, User -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from prowler.providers.m365.services.entra.entra_service import AdminRoles, User +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_admin_users_cloud_only: @@ -17,14 +15,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) @@ -72,14 +70,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) @@ -127,14 +125,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) @@ -182,14 +180,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) @@ -237,14 +235,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) @@ -293,14 +291,14 @@ class Test_entra_admin_users_cloud_only: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( + from prowler.providers.m365.services.entra.entra_admin_users_cloud_only.entra_admin_users_cloud_only import ( entra_admin_users_cloud_only, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py b/tests/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py similarity index 90% rename from tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py rename to tests/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py index 1a628de808..b25d48dd2c 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_admin_users_mfa_enabled/entra_admin_users_mfa_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicy, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_admin_users_mfa_enabled: @@ -31,14 +28,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -67,14 +64,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -143,14 +140,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -219,14 +216,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -300,14 +297,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -379,14 +376,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -474,14 +471,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) @@ -569,14 +566,14 @@ class Test_entra_admin_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_mfa_enabled.entra_admin_users_mfa_enabled import ( entra_admin_users_mfa_enabled, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py b/tests/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py similarity index 87% rename from tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py rename to tests/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py index 7d6c5987b1..aa9ec89bca 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_admin_users_phishing_resistant_mfa_enabled/entra_admin_users_phishing_resistant_mfa_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, AuthenticationStrength, ConditionalAccessGrantControl, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_admin_users_phishing_resistant_mfa_enabled: @@ -29,14 +26,14 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( entra_admin_users_phishing_resistant_mfa_enabled, ) @@ -65,17 +62,17 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( entra_admin_users_phishing_resistant_mfa_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -157,17 +154,17 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( entra_admin_users_phishing_resistant_mfa_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -252,17 +249,17 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_phishing_resistant_mfa_enabled.entra_admin_users_phishing_resistant_mfa_enabled import ( entra_admin_users_phishing_resistant_mfa_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py b/tests/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py similarity index 88% rename from tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py rename to tests/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py index 9c2cfa7aa1..ecfbf2b771 100644 --- a/tests/providers/microsoft365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_admin_users_sign_in_frequency_enabled/entra_admin_users_sign_in_frequency_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessPolicyState, Conditions, @@ -14,10 +14,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyType, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_admin_users_sign_in_frequency_enabled: @@ -28,14 +25,14 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) @@ -65,17 +62,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -140,17 +137,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -236,17 +233,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -333,17 +330,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -428,17 +425,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -524,17 +521,17 @@ class Test_entra_admin_users_sign_in_frequency_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( + from prowler.providers.m365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import ( entra_admin_users_sign_in_frequency_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py b/tests/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py similarity index 72% rename from tests/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py rename to tests/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py index 4069310f4a..6aa9de8004 100644 --- a/tests/providers/microsoft365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py +++ b/tests/providers/m365/services/entra/entra_dynamic_group_for_guests_created/entra_dynamic_group_for_guests_created_test.py @@ -1,9 +1,7 @@ from unittest import mock -from prowler.providers.microsoft365.services.entra.entra_service import Group -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from prowler.providers.m365.services.entra.entra_service import Group +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_dynamic_group_for_guests_created: @@ -18,14 +16,14 @@ class Test_entra_dynamic_group_for_guests_created: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", + "prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( + from prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( entra_dynamic_group_for_guests_created, ) @@ -43,10 +41,10 @@ class Test_entra_dynamic_group_for_guests_created: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", + "prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", new=entra_client, ), ): @@ -59,7 +57,7 @@ class Test_entra_dynamic_group_for_guests_created: ) ] - from prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( + from prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( entra_dynamic_group_for_guests_created, ) @@ -85,10 +83,10 @@ class Test_entra_dynamic_group_for_guests_created: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", + "prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created.entra_client", new=entra_client, ), ): @@ -101,7 +99,7 @@ class Test_entra_dynamic_group_for_guests_created: ) ] - from prowler.providers.microsoft365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( + from prowler.providers.m365.services.entra.entra_dynamic_group_for_guests_created.entra_dynamic_group_for_guests_created import ( entra_dynamic_group_for_guests_created, ) diff --git a/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py b/tests/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py similarity index 85% rename from tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py rename to tests/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py index a1c6c48f78..2bd84694ea 100644 --- a/tests/providers/microsoft365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_identity_protection_sign_in_risk_enabled/entra_identity_protection_sign_in_risk_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_identity_protection_sign_in_risk_enabled: @@ -29,14 +26,14 @@ class Test_entra_identity_protection_sign_in_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( entra_identity_protection_sign_in_risk_enabled, ) @@ -64,17 +61,17 @@ class Test_entra_identity_protection_sign_in_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( entra_identity_protection_sign_in_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -140,17 +137,17 @@ class Test_entra_identity_protection_sign_in_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( entra_identity_protection_sign_in_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -223,17 +220,17 @@ class Test_entra_identity_protection_sign_in_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( entra_identity_protection_sign_in_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -306,17 +303,17 @@ class Test_entra_identity_protection_sign_in_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_sign_in_risk_enabled.entra_identity_protection_sign_in_risk_enabled import ( entra_identity_protection_sign_in_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py b/tests/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py similarity index 85% rename from tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py rename to tests/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py index ead5b42d61..b251199af6 100644 --- a/tests/providers/microsoft365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_identity_protection_user_risk_enabled/entra_identity_protection_user_risk_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_identity_protection_user_risk_enabled: @@ -29,14 +26,14 @@ class Test_entra_identity_protection_user_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( entra_identity_protection_user_risk_enabled, ) @@ -64,17 +61,17 @@ class Test_entra_identity_protection_user_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( entra_identity_protection_user_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -139,17 +136,17 @@ class Test_entra_identity_protection_user_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( entra_identity_protection_user_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -221,17 +218,17 @@ class Test_entra_identity_protection_user_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( entra_identity_protection_user_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -303,17 +300,17 @@ class Test_entra_identity_protection_user_risk_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( + from prowler.providers.m365.services.entra.entra_identity_protection_user_risk_enabled.entra_identity_protection_user_risk_enabled import ( entra_identity_protection_user_risk_enabled, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py b/tests/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py similarity index 85% rename from tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py rename to tests/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py index 1b45102d23..b3b1a38550 100644 --- a/tests/providers/microsoft365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py +++ b/tests/providers/m365/services/entra/entra_legacy_authentication_blocked/entra_legacy_authentication_blocked_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ClientAppType, ConditionalAccessGrantControl, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_legacy_authentication_blocked: @@ -29,14 +26,14 @@ class Test_entra_legacy_authentication_blocked: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + "prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + from prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( entra_legacy_authentication_blocked, ) @@ -65,17 +62,17 @@ class Test_entra_legacy_authentication_blocked: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + "prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + from prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( entra_legacy_authentication_blocked, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -147,17 +144,17 @@ class Test_entra_legacy_authentication_blocked: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + "prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + from prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( entra_legacy_authentication_blocked, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -232,17 +229,17 @@ class Test_entra_legacy_authentication_blocked: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", + "prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( + from prowler.providers.m365.services.entra.entra_legacy_authentication_blocked.entra_legacy_authentication_blocked import ( entra_legacy_authentication_blocked, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py b/tests/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py similarity index 83% rename from tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py rename to tests/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py index d40986b56c..4f58579208 100644 --- a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py +++ b/tests/providers/m365/services/entra/entra_managed_device_required_for_authentication/entra_managed_device_required_for_authentication_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -14,10 +14,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_managed_device_required_for_authentication: @@ -28,14 +25,14 @@ class Test_entra_managed_device_required_for_authentication: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( entra_managed_device_required_for_authentication, ) @@ -63,17 +60,17 @@ class Test_entra_managed_device_required_for_authentication: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( entra_managed_device_required_for_authentication, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -137,17 +134,17 @@ class Test_entra_managed_device_required_for_authentication: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( entra_managed_device_required_for_authentication, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -219,17 +216,17 @@ class Test_entra_managed_device_required_for_authentication: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_authentication.entra_managed_device_required_for_authentication import ( entra_managed_device_required_for_authentication, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py b/tests/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py similarity index 83% rename from tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py rename to tests/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py index 11899eb574..a127e9859b 100644 --- a/tests/providers/microsoft365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py +++ b/tests/providers/m365/services/entra/entra_managed_device_required_for_mfa_registration/entra_managed_device_required_for_mfa_registration_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicyState, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( UserAction, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_managed_device_required_for_mfa_registration: @@ -29,14 +26,14 @@ class Test_entra_managed_device_required_for_mfa_registration: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( entra_managed_device_required_for_mfa_registration, ) @@ -64,17 +61,17 @@ class Test_entra_managed_device_required_for_mfa_registration: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( entra_managed_device_required_for_mfa_registration, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -138,17 +135,17 @@ class Test_entra_managed_device_required_for_mfa_registration: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( entra_managed_device_required_for_mfa_registration, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) @@ -220,17 +217,17 @@ class Test_entra_managed_device_required_for_mfa_registration: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", + "prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( + from prowler.providers.m365.services.entra.entra_managed_device_required_for_mfa_registration.entra_managed_device_required_for_mfa_registration import ( entra_managed_device_required_for_mfa_registration, ) - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( ConditionalAccessPolicy, ) diff --git a/tests/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py b/tests/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py similarity index 74% rename from tests/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py rename to tests/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py index bc9e5b3008..d4ec23bac3 100644 --- a/tests/providers/microsoft365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_password_hash_sync_enabled/entra_password_hash_sync_enabled_test.py @@ -1,9 +1,7 @@ from unittest import mock -from prowler.providers.microsoft365.services.entra.entra_service import Organization -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from prowler.providers.m365.services.entra.entra_service import Organization +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_password_hash_sync_enabled: @@ -13,14 +11,14 @@ class Test_entra_password_hash_sync_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( + from prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( entra_password_hash_sync_enabled, ) @@ -51,14 +49,14 @@ class Test_entra_password_hash_sync_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( + from prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( entra_password_hash_sync_enabled, ) @@ -103,14 +101,14 @@ class Test_entra_password_hash_sync_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( + from prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( entra_password_hash_sync_enabled, ) @@ -142,14 +140,14 @@ class Test_entra_password_hash_sync_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( + from prowler.providers.m365.services.entra.entra_password_hash_sync_enabled.entra_password_hash_sync_enabled import ( entra_password_hash_sync_enabled, ) diff --git a/tests/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py b/tests/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py similarity index 72% rename from tests/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py rename to tests/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py index 5c615b1da0..0e354e3e90 100644 --- a/tests/providers/microsoft365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py +++ b/tests/providers/m365/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/microsoft365_entra_policy_ensure_default_user_cannot_create_tenants_test.py @@ -1,13 +1,11 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, DefaultUserRolePermissions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_policy_ensure_default_user_cannot_create_tenants: @@ -18,14 +16,14 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", + "prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( + from prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( entra_policy_ensure_default_user_cannot_create_tenants, ) @@ -49,14 +47,14 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", + "prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( + from prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( entra_policy_ensure_default_user_cannot_create_tenants, ) @@ -89,14 +87,14 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", + "prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( + from prowler.providers.m365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( entra_policy_ensure_default_user_cannot_create_tenants, ) diff --git a/tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py b/tests/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py similarity index 75% rename from tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py rename to tests/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py index 27eec2d350..b92e051e68 100644 --- a/tests/providers/microsoft365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py +++ b/tests/providers/m365/services/entra/entra_policy_guest_invite_only_for_admin_roles/microsoft365_entra_policy_guest_invite_only_for_admin_roles_test.py @@ -1,12 +1,10 @@ import mock -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, InvitationsFrom, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_policy_guest_invite_only_for_admin_roles: @@ -21,14 +19,14 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + from prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( entra_policy_guest_invite_only_for_admin_roles, ) @@ -54,14 +52,14 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + from prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( entra_policy_guest_invite_only_for_admin_roles, ) @@ -95,14 +93,14 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + from prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( entra_policy_guest_invite_only_for_admin_roles, ) @@ -136,14 +134,14 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( + from prowler.providers.m365.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( entra_policy_guest_invite_only_for_admin_roles, ) diff --git a/tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py b/tests/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py similarity index 76% rename from tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py rename to tests/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py index c0b8f7af37..7eac966f69 100644 --- a/tests/providers/microsoft365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py +++ b/tests/providers/m365/services/entra/entra_policy_guest_users_access_restrictions/microsoft365_entra_policy_guest_users_access_restrictions_test.py @@ -1,12 +1,10 @@ from unittest import mock -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, AuthPolicyRoles, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_policy_guest_users_access_restrictions: @@ -21,14 +19,14 @@ class Test_entra_policy_guest_users_access_restrictions: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + from prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( entra_policy_guest_users_access_restrictions, ) @@ -54,14 +52,14 @@ class Test_entra_policy_guest_users_access_restrictions: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + from prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( entra_policy_guest_users_access_restrictions, ) @@ -95,14 +93,14 @@ class Test_entra_policy_guest_users_access_restrictions: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + from prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( entra_policy_guest_users_access_restrictions, ) @@ -136,14 +134,14 @@ class Test_entra_policy_guest_users_access_restrictions: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", + "prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( + from prowler.providers.m365.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( entra_policy_guest_users_access_restrictions, ) diff --git a/tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py b/tests/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py similarity index 79% rename from tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py rename to tests/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py index 5dd52ebace..e31d3b9113 100644 --- a/tests/providers/microsoft365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py +++ b/tests/providers/m365/services/entra/entra_policy_restricts_user_consent_for_apps/microsoft365_entra_policy_restricts_user_consent_for_apps_test.py @@ -1,13 +1,11 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, DefaultUserRolePermissions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider class Test_entra_policy_restricts_user_consent_for_apps: @@ -25,14 +23,14 @@ class Test_entra_policy_restricts_user_consent_for_apps: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + "prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + from prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( entra_policy_restricts_user_consent_for_apps, ) @@ -65,14 +63,14 @@ class Test_entra_policy_restricts_user_consent_for_apps: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + "prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + from prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( entra_policy_restricts_user_consent_for_apps, ) @@ -116,14 +114,14 @@ class Test_entra_policy_restricts_user_consent_for_apps: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", + "prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( + from prowler.providers.m365.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( entra_policy_restricts_user_consent_for_apps, ) diff --git a/tests/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py b/tests/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py similarity index 70% rename from tests/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py rename to tests/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py index 9d0d112b6a..d17644b134 100644 --- a/tests/providers/microsoft365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py +++ b/tests/providers/m365/services/entra/entra_thirdparty_integrated_apps_not_allowed/entra_thirdparty_integrated_apps_not_allowed_test.py @@ -1,13 +1,10 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( DefaultUserRolePermissions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_thirdparty_integrated_apps_not_allowed: @@ -18,14 +15,14 @@ class Test_entra_thirdparty_integrated_apps_not_allowed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", + "prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( + from prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( entra_thirdparty_integrated_apps_not_allowed, ) @@ -44,17 +41,17 @@ class Test_entra_thirdparty_integrated_apps_not_allowed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", + "prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, ) - from prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( + from prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( entra_thirdparty_integrated_apps_not_allowed, ) @@ -88,17 +85,17 @@ class Test_entra_thirdparty_integrated_apps_not_allowed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", + "prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_service import ( + from prowler.providers.m365.services.entra.entra_service import ( AuthorizationPolicy, ) - from prowler.providers.microsoft365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( + from prowler.providers.m365.services.entra.entra_thirdparty_integrated_apps_not_allowed.entra_thirdparty_integrated_apps_not_allowed import ( entra_thirdparty_integrated_apps_not_allowed, ) diff --git a/tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py b/tests/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py similarity index 87% rename from tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py rename to tests/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py index 7552cea160..07699fdecf 100644 --- a/tests/providers/microsoft365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py +++ b/tests/providers/m365/services/entra/entra_users_mfa_enabled/entra_users_mfa_enabled_test.py @@ -1,7 +1,7 @@ from unittest import mock from uuid import uuid4 -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.services.entra.entra_service import ( ApplicationsConditions, ConditionalAccessGrantControl, ConditionalAccessPolicy, @@ -15,10 +15,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( SignInFrequencyInterval, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_entra_users_mfa_enabled: @@ -31,14 +28,14 @@ class Test_entra_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( entra_users_mfa_enabled, ) @@ -67,14 +64,14 @@ class Test_entra_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( entra_users_mfa_enabled, ) @@ -148,14 +145,14 @@ class Test_entra_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( entra_users_mfa_enabled, ) @@ -227,14 +224,14 @@ class Test_entra_users_mfa_enabled: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", + "prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled.entra_client", new=entra_client, ), ): - from prowler.providers.microsoft365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( + from prowler.providers.m365.services.entra.entra_users_mfa_enabled.entra_users_mfa_enabled import ( entra_users_mfa_enabled, ) diff --git a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py b/tests/providers/m365/services/entra/microsoft365_entra_service_test.py similarity index 88% rename from tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py rename to tests/providers/m365/services/entra/microsoft365_entra_service_test.py index 8c9e8128c1..98fbed8e35 100644 --- a/tests/providers/microsoft365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/m365/services/entra/microsoft365_entra_service_test.py @@ -1,7 +1,7 @@ from unittest.mock import patch -from prowler.providers.microsoft365.models import Microsoft365IdentityInfo -from prowler.providers.microsoft365.services.entra.entra_service import ( +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.entra.entra_service import ( AdminConsentPolicy, AdminRoles, ApplicationsConditions, @@ -27,10 +27,7 @@ from prowler.providers.microsoft365.services.entra.entra_service import ( UserAction, UsersConditions, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider async def mock_entra_get_authorization_policy(_): @@ -153,18 +150,16 @@ async def mock_entra_get_organization(_): class Test_Entra_Service: def test_get_client(self): admincenter_client = Entra( - set_mocked_microsoft365_provider( - identity=Microsoft365IdentityInfo(tenant_domain=DOMAIN) - ) + set_mocked_m365_provider(identity=M365IdentityInfo(tenant_domain=DOMAIN)) ) assert admincenter_client.client.__class__.__name__ == "GraphServiceClient" @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_authorization_policy", + "prowler.providers.m365.services.entra.entra_service.Entra._get_authorization_policy", new=mock_entra_get_authorization_policy, ) def test_get_authorization_policy(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert entra_client.authorization_policy.id == "id-1" assert entra_client.authorization_policy.name == "Name 1" assert entra_client.authorization_policy.description == "Description 1" @@ -188,11 +183,11 @@ class Test_Entra_Service: ) @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_conditional_access_policies", + "prowler.providers.m365.services.entra.entra_service.Entra._get_conditional_access_policies", new=mock_entra_get_conditional_access_policies, ) def test_get_conditional_access_policies(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert entra_client.conditional_access_policies == { "id-1": ConditionalAccessPolicy( id="id-1", @@ -234,11 +229,11 @@ class Test_Entra_Service: } @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_groups", + "prowler.providers.m365.services.entra.entra_service.Entra._get_groups", new=mock_entra_get_groups, ) def test_get_groups(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert len(entra_client.groups) == 2 assert entra_client.groups[0]["id"] == "id-1" assert entra_client.groups[0]["name"] == "group1" @@ -250,33 +245,33 @@ class Test_Entra_Service: assert entra_client.groups[1]["membershipRule"] == "" @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_admin_consent_policy", + "prowler.providers.m365.services.entra.entra_service.Entra._get_admin_consent_policy", new=mock_entra_get_admin_consent_policy, ) def test_get_admin_consent_policy(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert entra_client.admin_consent_policy.admin_consent_enabled assert entra_client.admin_consent_policy.notify_reviewers assert entra_client.admin_consent_policy.email_reminders_to_reviewers is False assert entra_client.admin_consent_policy.duration_in_days == 30 @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_organization", + "prowler.providers.m365.services.entra.entra_service.Entra._get_organization", new=mock_entra_get_organization, ) def test_get_organization(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert len(entra_client.organizations) == 1 assert entra_client.organizations[0].id == "org1" assert entra_client.organizations[0].name == "Organization 1" assert entra_client.organizations[0].on_premises_sync_enabled @patch( - "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_users", + "prowler.providers.m365.services.entra.entra_service.Entra._get_users", new=mock_entra_get_users, ) def test_get_users(self): - entra_client = Entra(set_mocked_microsoft365_provider()) + entra_client = Entra(set_mocked_m365_provider()) assert len(entra_client.users) == 3 assert entra_client.users["user-1"].id == "user-1" assert entra_client.users["user-1"].name == "User 1" diff --git a/tests/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled_test.py b/tests/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled_test.py new file mode 100644 index 0000000000..0a4fc78894 --- /dev/null +++ b/tests/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled_test.py @@ -0,0 +1,82 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_purview_audit_log_search_enabled: + def test_audit_log_search_disabled(self): + purview_client = mock.MagicMock() + purview_client.audited_tenant = "audited_tenant" + purview_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.purview.purview_audit_log_search_enabled.purview_audit_log_search_enabled.purview_client", + new=purview_client, + ), + ): + from prowler.providers.m365.services.purview.purview_audit_log_search_enabled.purview_audit_log_search_enabled import ( + purview_audit_log_search_enabled, + ) + from prowler.providers.m365.services.purview.purview_service import ( + AuditLogConfig, + ) + + purview_client.audit_log_config = AuditLogConfig(audit_log_search=False) + + check = purview_audit_log_search_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended == "Purview audit log search is not enabled." + ) + assert result[0].resource == purview_client.audit_log_config.dict() + assert result[0].resource_name == "Purview Settings" + assert result[0].resource_id == "purviewSettings" + assert result[0].location == "global" + purview_client.powershell.close() + + def test_audit_log_search_enabled(self): + purview_client = mock.MagicMock() + purview_client.audited_tenant = "audited_tenant" + purview_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.purview.purview_audit_log_search_enabled.purview_audit_log_search_enabled.purview_client", + new=purview_client, + ), + ): + from prowler.providers.m365.services.purview.purview_audit_log_search_enabled.purview_audit_log_search_enabled import ( + purview_audit_log_search_enabled, + ) + from prowler.providers.m365.services.purview.purview_service import ( + AuditLogConfig, + ) + + purview_client.audit_log_config = AuditLogConfig(audit_log_search=True) + + check = purview_audit_log_search_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == "Purview audit log search is enabled." + assert result[0].resource == purview_client.audit_log_config.dict() + assert result[0].resource_name == "Purview Settings" + assert result[0].resource_id == "purviewSettings" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/purview/purview_service_test.py b/tests/providers/m365/services/purview/purview_service_test.py new file mode 100644 index 0000000000..9d1a9f9414 --- /dev/null +++ b/tests/providers/m365/services/purview/purview_service_test.py @@ -0,0 +1,48 @@ +from unittest import mock +from unittest.mock import patch + +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.purview.purview_service import ( + AuditLogConfig, + Purview, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +def mock_get_audit_log_config(_): + return AuditLogConfig(audit_log_search=True) + + +class Test_Purview_Service: + def test_get_client(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + purview_client = Purview( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert purview_client.client.__class__.__name__ == "GraphServiceClient" + assert purview_client.powershell.__class__.__name__ == "M365PowerShell" + + @patch( + "prowler.providers.m365.services.purview.purview_service.Purview._get_audit_log_config", + new=mock_get_audit_log_config, + ) + def test_get_settings(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + purview_client = Purview( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert purview_client.audit_log_config == AuditLogConfig( + audit_log_search=True + ) diff --git a/tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py similarity index 78% rename from tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py rename to tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py index 35f8a33478..6111ff0993 100644 --- a/tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py @@ -1,12 +1,9 @@ from unittest import mock -from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( +from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePointSettings, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_sharepoint_external_sharing_managed: @@ -20,14 +17,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) @@ -65,14 +62,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) @@ -110,14 +107,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) @@ -155,14 +152,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) @@ -200,14 +197,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) @@ -247,14 +244,14 @@ class Test_sharepoint_external_sharing_managed: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_managed.sharepoint_external_sharing_managed import ( sharepoint_external_sharing_managed, ) diff --git a/tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py similarity index 75% rename from tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py rename to tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py index 98c749cd79..f238cbf4fa 100644 --- a/tests/providers/microsoft365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py @@ -1,12 +1,9 @@ from unittest import mock -from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( +from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePointSettings, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_sharepoint_external_sharing_restricted: @@ -20,14 +17,14 @@ class Test_sharepoint_external_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( sharepoint_external_sharing_restricted, ) @@ -63,14 +60,14 @@ class Test_sharepoint_external_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( sharepoint_external_sharing_restricted, ) @@ -108,14 +105,14 @@ class Test_sharepoint_external_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_external_sharing_restricted.sharepoint_external_sharing_restricted import ( sharepoint_external_sharing_restricted, ) diff --git a/tests/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py b/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py similarity index 74% rename from tests/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py rename to tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py index 0230f21db3..1386278fa6 100644 --- a/tests/providers/microsoft365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py @@ -1,12 +1,9 @@ from unittest import mock -from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( +from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePointSettings, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_sharepoint_guest_sharing_restricted: @@ -20,14 +17,14 @@ class Test_sharepoint_guest_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( sharepoint_guest_sharing_restricted, ) @@ -64,14 +61,14 @@ class Test_sharepoint_guest_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( sharepoint_guest_sharing_restricted, ) @@ -110,14 +107,14 @@ class Test_sharepoint_guest_sharing_restricted: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( + from prowler.providers.m365.services.sharepoint.sharepoint_guest_sharing_restricted.sharepoint_guest_sharing_restricted import ( sharepoint_guest_sharing_restricted, ) diff --git a/tests/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py b/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py similarity index 73% rename from tests/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py rename to tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py index 6e0199e0b2..bf2c23a645 100644 --- a/tests/providers/microsoft365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py @@ -1,9 +1,6 @@ from unittest import mock -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_sharepoint_modern_authentication_required: @@ -17,17 +14,17 @@ class Test_sharepoint_modern_authentication_required: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( + from prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( sharepoint_modern_authentication_required, ) - from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( + from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePointSettings, ) @@ -63,17 +60,17 @@ class Test_sharepoint_modern_authentication_required: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( + from prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( sharepoint_modern_authentication_required, ) - from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( + from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePointSettings, ) @@ -111,14 +108,14 @@ class Test_sharepoint_modern_authentication_required: with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_microsoft365_provider(), + return_value=set_mocked_m365_provider(), ), mock.patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", + "prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required.sharepoint_client", new=sharepoint_client, ), ): - from prowler.providers.microsoft365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( + from prowler.providers.m365.services.sharepoint.sharepoint_modern_authentication_required.sharepoint_modern_authentication_required import ( sharepoint_modern_authentication_required, ) diff --git a/tests/providers/microsoft365/services/sharepoint/sharepoint_service_test.py b/tests/providers/m365/services/sharepoint/sharepoint_service_test.py similarity index 66% rename from tests/providers/microsoft365/services/sharepoint/sharepoint_service_test.py rename to tests/providers/m365/services/sharepoint/sharepoint_service_test.py index 06a220f2c8..8c3dc72598 100644 --- a/tests/providers/microsoft365/services/sharepoint/sharepoint_service_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_service_test.py @@ -1,14 +1,11 @@ from unittest.mock import patch -from prowler.providers.microsoft365.models import Microsoft365IdentityInfo -from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import ( +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.sharepoint.sharepoint_service import ( SharePoint, SharePointSettings, ) -from tests.providers.microsoft365.microsoft365_fixtures import ( - DOMAIN, - set_mocked_microsoft365_provider, -) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider async def mock_sharepoint_get_settings(_): @@ -23,20 +20,18 @@ async def mock_sharepoint_get_settings(_): @patch( - "prowler.providers.microsoft365.services.sharepoint.sharepoint_service.SharePoint._get_settings", + "prowler.providers.m365.services.sharepoint.sharepoint_service.SharePoint._get_settings", new=mock_sharepoint_get_settings, ) class Test_SharePoint_Service: def test_get_client(self): sharepoint_client = SharePoint( - set_mocked_microsoft365_provider( - identity=Microsoft365IdentityInfo(tenant_domain=DOMAIN) - ) + set_mocked_m365_provider(identity=M365IdentityInfo(tenant_domain=DOMAIN)) ) assert sharepoint_client.client.__class__.__name__ == "GraphServiceClient" def test_get_settings(self): - sharepoint_client = SharePoint(set_mocked_microsoft365_provider()) + sharepoint_client = SharePoint(set_mocked_m365_provider()) settings = sharepoint_client.settings assert settings.sharingCapability == "ExternalUserAndGuestSharing" assert settings.sharingAllowedDomainList == ["allowed-domain.com"] diff --git a/tests/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted_test.py b/tests/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted_test.py new file mode 100644 index 0000000000..ea8d35f189 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted_test.py @@ -0,0 +1,121 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_external_file_sharing_restricted: + def test_file_sharing_no_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_file_sharing_restricted.teams_external_file_sharing_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_file_sharing_restricted.teams_external_file_sharing_restricted import ( + teams_external_file_sharing_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import ( + CloudStorageSettings, + TeamsSettings, + ) + + teams_client.teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=True, + allow_drop_box=True, + allow_egnyte=True, + allow_google_drive=True, + allow_share_file=True, + ) + ) + + teams_client.audit_config = {"allowed_cloud_storage_services": []} + + check = teams_external_file_sharing_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External file sharing is not restricted to only approved cloud storage services." + ) + assert ( + result[0].resource + == teams_client.teams_settings.cloud_storage_settings.dict() + ) + assert result[0].resource_name == "Cloud Storage Settings" + assert result[0].resource_id == "cloudStorageSettings" + assert result[0].location == "global" + + def test_file_sharing_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_file_sharing_restricted.teams_external_file_sharing_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_file_sharing_restricted.teams_external_file_sharing_restricted import ( + teams_external_file_sharing_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import ( + CloudStorageSettings, + TeamsSettings, + ) + + teams_client.teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=True, + allow_drop_box=True, + allow_egnyte=False, + allow_google_drive=True, + allow_share_file=True, + ) + ) + + teams_client.audit_config = { + "allowed_cloud_storage_services": [ + "allow_box", + "allow_drop_box", + # "allow_egnyte", + "allow_google_drive", + "allow_share_file", + ] + } + + check = teams_external_file_sharing_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External file sharing is restricted to only approved cloud storage services." + ) + assert ( + result[0].resource + == teams_client.teams_settings.cloud_storage_settings.dict() + ) + assert result[0].resource_name == "Cloud Storage Settings" + assert result[0].resource_id == "cloudStorageSettings" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py new file mode 100644 index 0000000000..73d6425433 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -0,0 +1,65 @@ +from unittest import mock +from unittest.mock import patch + +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.teams.teams_service import ( + CloudStorageSettings, + Teams, + TeamsSettings, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +def mock_get_teams_client_configuration(_): + return TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=False, + allow_drop_box=False, + allow_egnyte=False, + allow_google_drive=False, + allow_share_file=False, + ) + ) + + +class Test_Teams_Service: + def test_get_client(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + ): + teams_client = Teams( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert teams_client.client.__class__.__name__ == "GraphServiceClient" + assert teams_client.powershell.__class__.__name__ == "M365PowerShell" + teams_client.powershell.close() + + @patch( + "prowler.providers.m365.services.teams.teams_service.Teams._get_teams_client_configuration", + new=mock_get_teams_client_configuration, + ) + def test_get_settings(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + ): + teams_client = Teams( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert teams_client.teams_settings == TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=False, + allow_drop_box=False, + allow_egnyte=False, + allow_google_drive=False, + allow_share_file=False, + ) + ) + teams_client.powershell.close() diff --git a/tests/providers/microsoft365/microsoft365_provider_test.py b/tests/providers/microsoft365/microsoft365_provider_test.py deleted file mode 100644 index 7658301e44..0000000000 --- a/tests/providers/microsoft365/microsoft365_provider_test.py +++ /dev/null @@ -1,312 +0,0 @@ -from unittest.mock import patch -from uuid import uuid4 - -import pytest -from azure.core.credentials import AccessToken -from azure.identity import ( - ClientSecretCredential, - DefaultAzureCredential, - InteractiveBrowserCredential, -) -from mock import MagicMock - -from prowler.config.config import ( - default_config_file_path, - default_fixer_config_file_path, - load_and_validate_config_file, -) -from prowler.providers.common.models import Connection -from prowler.providers.microsoft365.exceptions.exceptions import ( - Microsoft365HTTPResponseError, - Microsoft365NoAuthenticationMethodError, -) -from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider -from prowler.providers.microsoft365.models import ( - Microsoft365IdentityInfo, - Microsoft365RegionConfig, -) -from tests.providers.microsoft365.microsoft365_fixtures import ( - CLIENT_ID, - CLIENT_SECRET, - DOMAIN, - IDENTITY_ID, - IDENTITY_TYPE, - LOCATION, - TENANT_ID, -) - - -class TestMicrosoft365Provider: - def test_microsoft365_provider(self): - tenant_id = None - client_id = None - client_secret = None - - fixer_config = load_and_validate_config_file( - "microsoft365", default_fixer_config_file_path - ) - azure_region = "Microsoft365Global" - - with ( - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session", - return_value=ClientSecretCredential( - client_id=CLIENT_ID, - tenant_id=TENANT_ID, - client_secret=CLIENT_SECRET, - ), - ), - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_identity", - return_value=Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type=IDENTITY_TYPE, - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ), - ), - ): - microsoft365_provider = Microsoft365Provider( - sp_env_auth=True, - az_cli_auth=False, - browser_auth=False, - tenant_id=tenant_id, - client_id=client_id, - client_secret=client_secret, - region=azure_region, - config_path=default_config_file_path, - fixer_config=fixer_config, - ) - - assert microsoft365_provider.region_config == Microsoft365RegionConfig( - name="Microsoft365Global", - authority=None, - base_url="https://graph.microsoft.com", - credential_scopes=["https://graph.microsoft.com/.default"], - ) - assert microsoft365_provider.identity == Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type=IDENTITY_TYPE, - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ) - - def test_microsoft365_provider_cli_auth(self): - """Test Microsoft365 Provider initialization with CLI authentication""" - azure_region = "Microsoft365Global" - fixer_config = load_and_validate_config_file( - "microsoft365", default_fixer_config_file_path - ) - - with ( - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session", - return_value=DefaultAzureCredential( - exclude_environment_credential=True, - exclude_cli_credential=False, - exclude_managed_identity_credential=True, - exclude_visual_studio_code_credential=True, - exclude_shared_token_cache_credential=True, - exclude_powershell_credential=True, - exclude_browser_credential=True, - ), - ), - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_identity", - return_value=Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type="User", - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ), - ), - ): - microsoft365_provider = Microsoft365Provider( - sp_env_auth=False, - az_cli_auth=True, - browser_auth=False, - region=azure_region, - config_path=default_config_file_path, - fixer_config=fixer_config, - ) - - assert microsoft365_provider.region_config == Microsoft365RegionConfig( - name="Microsoft365Global", - authority=None, - base_url="https://graph.microsoft.com", - credential_scopes=["https://graph.microsoft.com/.default"], - ) - assert microsoft365_provider.identity == Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type="User", - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ) - assert isinstance(microsoft365_provider.session, DefaultAzureCredential) - - def test_microsoft365_provider_browser_auth(self): - """Test Microsoft365 Provider initialization with Browser authentication""" - azure_region = "Microsoft365Global" - fixer_config = load_and_validate_config_file( - "microsoft365", default_fixer_config_file_path - ) - - with ( - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session", - return_value=InteractiveBrowserCredential( - tenant_id=TENANT_ID, - ), - ), - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_identity", - return_value=Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type="User", - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ), - ), - ): - microsoft365_provider = Microsoft365Provider( - sp_env_auth=False, - az_cli_auth=False, - browser_auth=True, - tenant_id=TENANT_ID, - region=azure_region, - config_path=default_config_file_path, - fixer_config=fixer_config, - ) - - assert microsoft365_provider.region_config == Microsoft365RegionConfig( - name="Microsoft365Global", - authority=None, - base_url="https://graph.microsoft.com", - credential_scopes=["https://graph.microsoft.com/.default"], - ) - assert microsoft365_provider.identity == Microsoft365IdentityInfo( - identity_id=IDENTITY_ID, - identity_type="User", - tenant_id=TENANT_ID, - tenant_domain=DOMAIN, - location=LOCATION, - ) - assert isinstance( - microsoft365_provider.session, InteractiveBrowserCredential - ) - - def test_test_connection_browser_auth(self): - with ( - patch( - "prowler.providers.microsoft365.microsoft365_provider.DefaultAzureCredential" - ) as mock_default_credential, - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session" - ) as mock_setup_session, - patch( - "prowler.providers.microsoft365.microsoft365_provider.GraphServiceClient" - ) as mock_graph_client, - ): - # Mock the return value of DefaultAzureCredential - mock_credentials = MagicMock() - mock_credentials.get_token.return_value = AccessToken( - token="fake_token", expires_on=9999999999 - ) - mock_default_credential.return_value = mock_credentials - - # Mock setup_session to return a mocked session object - mock_session = MagicMock() - mock_setup_session.return_value = mock_session - - # Mock GraphServiceClient to avoid real API calls - mock_client = MagicMock() - mock_graph_client.return_value = mock_client - - test_connection = Microsoft365Provider.test_connection( - browser_auth=True, - tenant_id=str(uuid4()), - region="Microsoft365Global", - raise_on_exception=False, - ) - - assert isinstance(test_connection, Connection) - assert test_connection.is_connected - assert test_connection.error is None - - def test_test_connection_tenant_id_client_id_client_secret(self): - with ( - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session" - ) as mock_setup_session, - patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.validate_static_credentials" - ) as mock_validate_static_credentials, - ): - # Mock setup_session to return a mocked session object - mock_session = MagicMock() - mock_setup_session.return_value = mock_session - - # Mock ValidateStaticCredentials to avoid real API calls - mock_validate_static_credentials.return_value = None - - test_connection = Microsoft365Provider.test_connection( - tenant_id=str(uuid4()), - region="Microsoft365Global", - raise_on_exception=False, - client_id=str(uuid4()), - client_secret=str(uuid4()), - ) - - assert isinstance(test_connection, Connection) - assert test_connection.is_connected - assert test_connection.error is None - - def test_test_connection_with_httpresponseerror(self): - with patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session" - ) as mock_setup_session: - mock_setup_session.side_effect = Microsoft365HTTPResponseError( - file="test_file", original_exception="Simulated HttpResponseError" - ) - - with pytest.raises(Microsoft365HTTPResponseError) as exception: - Microsoft365Provider.test_connection( - az_cli_auth=True, - raise_on_exception=True, - ) - - assert exception.type == Microsoft365HTTPResponseError - assert ( - exception.value.args[0] - == "[6003] Error in HTTP response from Microsoft365 - Simulated HttpResponseError" - ) - - def test_test_connection_with_exception(self): - with patch( - "prowler.providers.microsoft365.microsoft365_provider.Microsoft365Provider.setup_session" - ) as mock_setup_session: - mock_setup_session.side_effect = Exception("Simulated Exception") - - with pytest.raises(Exception) as exception: - Microsoft365Provider.test_connection( - sp_env_auth=True, - raise_on_exception=True, - ) - - assert exception.type is Exception - assert exception.value.args[0] == "Simulated Exception" - - def test_test_connection_without_any_method(self): - with pytest.raises(Microsoft365NoAuthenticationMethodError) as exception: - Microsoft365Provider.test_connection() - - assert exception.type == Microsoft365NoAuthenticationMethodError - assert ( - "Microsoft365 provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth]" - in exception.value.args[0] - ) diff --git a/util/generate_compliance_json_from_csv_for_cis40_microsoft365.py b/util/generate_compliance_json_from_csv_for_cis40_microsoft365.py index c6ba8c101f..11a1dd8cca 100644 --- a/util/generate_compliance_json_from_csv_for_cis40_microsoft365.py +++ b/util/generate_compliance_json_from_csv_for_cis40_microsoft365.py @@ -2,7 +2,7 @@ import csv import json import sys -# Convert a CSV file following the CIS 4.0 Microsoft365 Benchmark into a Prowler v3.0 Compliance JSON file +# Convert a CSV file following the CIS 4.0 M365 Benchmark into a Prowler v3.0 Compliance JSON file # CSV fields: # Section #,Recommendation #,Profile,Title,Assessment Status,Description,Rationale Statement,Impact Statement,Remediation Procedure,Audit Procedure,Additional Information,CIS Controls,CIS Safeguards 1 (v8),CIS Safeguards 2 (v8),CIS Safeguards 3 (v8),v8 IG1,v8 IG2,v8 IG3,CIS Safeguards 1 (v7),CIS Safeguards 2 (v7),CIS Safeguards 3 (v7),v7 IG1,v7 IG2,v7 IG3,References,Default Value @@ -68,7 +68,7 @@ except UnicodeDecodeError: ) # Save the output JSON file -with open("cis_4.0_microsoft365.json", "w", encoding="utf-8") as outfile: +with open("cis_4.0_m365.json", "w", encoding="utf-8") as outfile: json.dump(output, outfile, indent=4, ensure_ascii=False) print("Archivo JSON generado exitosamente.") From d4c12e46321ce3ac723776231a7164fba0684ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Tue, 15 Apr 2025 19:25:37 +0200 Subject: [PATCH 167/359] fix(iam): change some logger.info values (#7526) Co-authored-by: Pepe Fagoaga Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 2 ++ prowler/providers/aws/services/iam/iam_service.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 441ca9979a..7964df1eec 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -14,6 +14,8 @@ All notable changes to the **Prowler SDK** are documented in this file. - Fix package name location in pyproject.toml while replicating for prowler-cloud [(#7531)](https://github.com/prowler-cloud/prowler/pull/7531). - Remove cache in PyPI release action [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532). +- Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). + --- ## [v5.5.1] (Prowler v5.5.1) diff --git a/prowler/providers/aws/services/iam/iam_service.py b/prowler/providers/aws/services/iam/iam_service.py index dc3ddd7bc8..2601377cfe 100644 --- a/prowler/providers/aws/services/iam/iam_service.py +++ b/prowler/providers/aws/services/iam/iam_service.py @@ -286,7 +286,7 @@ class IAM(AWSService): return stored_password_policy def _get_users(self): - logger.info("IAM - List Users...") + logger.info("IAM - Get Users...") try: get_users_paginator = self.client.get_paginator("list_users") users = [] @@ -469,7 +469,7 @@ class IAM(AWSService): ) def _list_attached_role_policies(self): - logger.info("IAM - List Attached User Policies...") + logger.info("IAM - List Attached Role Policies...") try: if self.roles: for role in self.roles: @@ -712,7 +712,7 @@ class IAM(AWSService): return roles def _list_entities_for_policy(self, policy_arn): - logger.info("IAM - List Entities Role For Policy...") + logger.info("IAM - List Entities For Policy...") try: entities = { "Users": [], From 19476632ff0265d9d913d3d7604b477b3db258e4 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 16 Apr 2025 01:41:57 -0400 Subject: [PATCH 168/359] chore(dependabot): change settings (#7536) --- .github/dependabot.yml | 93 +++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7fcf8e46d7..f4f12db90b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,8 +9,8 @@ updates: - package-ecosystem: "pip" directory: "/" schedule: - interval: "daily" - open-pull-requests-limit: 10 + interval: "monthly" + open-pull-requests-limit: 25 target-branch: master labels: - "dependencies" @@ -31,8 +31,8 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "daily" - open-pull-requests-limit: 10 + interval: "monthly" + open-pull-requests-limit: 25 target-branch: master labels: - "dependencies" @@ -53,46 +53,47 @@ updates: - package-ecosystem: "docker" directory: "/" schedule: - interval: "weekly" - open-pull-requests-limit: 10 + interval: "monthly" + open-pull-requests-limit: 25 target-branch: master labels: - "dependencies" - "docker" + # Dependabot Updates are temporary disabled - 2025/04/15 # v4.6 - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 10 - target-branch: v4.6 - labels: - - "dependencies" - - "pip" - - "v4" + # - package-ecosystem: "pip" + # directory: "/" + # schedule: + # interval: "weekly" + # open-pull-requests-limit: 10 + # target-branch: v4.6 + # labels: + # - "dependencies" + # - "pip" + # - "v4" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 10 - target-branch: v4.6 - labels: - - "dependencies" - - "github_actions" - - "v4" + # - package-ecosystem: "github-actions" + # directory: "/" + # schedule: + # interval: "weekly" + # open-pull-requests-limit: 10 + # target-branch: v4.6 + # labels: + # - "dependencies" + # - "github_actions" + # - "v4" - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 10 - target-branch: v4.6 - labels: - - "dependencies" - - "docker" - - "v4" + # - package-ecosystem: "docker" + # directory: "/" + # schedule: + # interval: "weekly" + # open-pull-requests-limit: 10 + # target-branch: v4.6 + # labels: + # - "dependencies" + # - "docker" + # - "v4" # Dependabot Updates are temporary disabled - 2025/03/19 # v3 @@ -107,13 +108,13 @@ updates: # - "pip" # - "v3" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "monthly" - open-pull-requests-limit: 10 - target-branch: v3 - labels: - - "dependencies" - - "github_actions" - - "v3" + # - package-ecosystem: "github-actions" + # directory: "/" + # schedule: + # interval: "monthly" + # open-pull-requests-limit: 10 + # target-branch: v3 + # labels: + # - "dependencies" + # - "github_actions" + # - "v3" From 6439f0a5f3507fdf81faa0b3181cf817e51ed8a0 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Wed, 16 Apr 2025 15:25:29 +0200 Subject: [PATCH 169/359] chore(regions_update): Changes in regions for AWS services (#7538) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 5811a41495..633973067d 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -939,6 +939,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -952,6 +953,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", From 32d27df0baf52c0cf7c9e7e486f118f0818775a7 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 16 Apr 2025 09:35:30 -0400 Subject: [PATCH 170/359] chore(regions): change interval to weekly (#7539) --- .github/workflows/sdk-refresh-aws-services-regions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index 9a9d01ea0a..cc0fdab1e1 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -4,7 +4,7 @@ name: SDK - Refresh AWS services' regions on: schedule: - - cron: "0 9 * * *" #runs at 09:00 UTC everyday + - cron: "0 9 * * 1" # runs at 09:00 UTC every Monday env: GITHUB_BRANCH: "master" From aa3182ebc55e01dbaddf191374e201e4c65a2464 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 16 Apr 2025 10:35:04 -0400 Subject: [PATCH 171/359] feat(gcp): support CLOUDSDK_AUTH_ACCESS_TOKEN (#7495) --- docs/tutorials/gcp/authentication.md | 44 +++++++++++++++++++++++- prowler/CHANGELOG.md | 1 + prowler/providers/gcp/gcp_provider.py | 11 ++++-- tests/providers/gcp/gcp_provider_test.py | 20 +++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/gcp/authentication.md b/docs/tutorials/gcp/authentication.md index 95c026decf..971796a753 100644 --- a/docs/tutorials/gcp/authentication.md +++ b/docs/tutorials/gcp/authentication.md @@ -4,8 +4,13 @@ Prowler will use by default your User Account credentials, you can configure it - `gcloud init` to use a new account - `gcloud config set account ` to use an existing account +- `gcloud auth application-default login` -Then, obtain your access credentials using: `gcloud auth application-default login` +This will generate Application Default Credentials (ADC) that Prowler will use automatically. + +--- + +## Using a Service Account key file Otherwise, you can generate and download Service Account keys in JSON format (refer to https://cloud.google.com/iam/docs/creating-managing-service-account-keys) and provide the location of the file with the following argument: @@ -16,6 +21,43 @@ prowler gcp --credentials-file path ???+ note `prowler` will scan the GCP project associated with the credentials. +--- + +## Using an access token + +If you already have an access token (e.g., generated with `gcloud auth print-access-token`), you can run Prowler with: + +```bash +export CLOUDSDK_AUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) +prowler gcp --project-ids +``` + +???+ note + If using this method, it's recommended to also set the default project explicitly: + ```bash + export GOOGLE_CLOUD_PROJECT= + ``` + +--- + +## Credentials lookup order + +Prowler follows the same search order as [Google authentication libraries](https://cloud.google.com/docs/authentication/application-default-credentials#search_order): + +1. [`GOOGLE_APPLICATION_CREDENTIALS` environment variable](https://cloud.google.com/docs/authentication/application-default-credentials#GAC) +2. [`CLOUDSDK_AUTH_ACCESS_TOKEN` + optional `GOOGLE_CLOUD_PROJECT`](https://cloud.google.com/sdk/gcloud/reference/auth/print-access-token) +3. [User credentials set up by using the Google Cloud CLI](https://cloud.google.com/docs/authentication/application-default-credentials#personal) +4. [Attached service account (e.g., Cloud Run, GCE, Cloud Functions)](https://cloud.google.com/docs/authentication/application-default-credentials#attached-sa) + +???+ note + The credentials must belong to a user or service account with the necessary permissions. + To ensure full access, assign the roles/viewer IAM role to the identity being used. + +???+ note + Prowler will use the enabled Google Cloud APIs to get the information needed to perform the checks. + +--- + ## Needed permissions diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 7964df1eec..a3edc2e94a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). +- Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) ### Fixed diff --git a/prowler/providers/gcp/gcp_provider.py b/prowler/providers/gcp/gcp_provider.py index 4ba25277d3..789c434bb4 100644 --- a/prowler/providers/gcp/gcp_provider.py +++ b/prowler/providers/gcp/gcp_provider.py @@ -396,14 +396,19 @@ class GcpProvider(Provider): client_secrets_path = os.path.abspath(credentials_file) os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = client_secrets_path + access_token = os.getenv("CLOUDSDK_AUTH_ACCESS_TOKEN") + if access_token: + logger.info("Using access token from CLOUDSDK_AUTH_ACCESS_TOKEN") + credentials = Credentials(token=access_token, scopes=scopes) + default_project_id = os.getenv("GOOGLE_CLOUD_PROJECT", "") + return credentials, default_project_id + # Get default credentials credentials, default_project_id = default(scopes=scopes) # Refresh the credentials to ensure they are valid credentials.refresh(Request()) - logger.info(f"Initial credentials: {credentials}") - if service_account: # Create the impersonated credentials credentials = impersonated_credentials.Credentials( @@ -411,7 +416,7 @@ class GcpProvider(Provider): target_principal=service_account, target_scopes=scopes, ) - logger.info(f"Impersonated credentials: {credentials}") + logger.info(f"Impersonating service account: {service_account}") return credentials, default_project_id except Exception as error: diff --git a/tests/providers/gcp/gcp_provider_test.py b/tests/providers/gcp/gcp_provider_test.py index e3c7644f17..8a10350d7d 100644 --- a/tests/providers/gcp/gcp_provider_test.py +++ b/tests/providers/gcp/gcp_provider_test.py @@ -323,6 +323,26 @@ class TestGCPProvider: == "test-impersonate-service-account" ) + def test_setup_session_with_access_token(self, monkeypatch): + from google.oauth2.credentials import Credentials as TokenCredentials + + access_token = "fake-access-token" + default_project_id = "test-access-token-project" + + monkeypatch.setenv("CLOUDSDK_AUTH_ACCESS_TOKEN", access_token) + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", default_project_id) + + session, project_id = GcpProvider.setup_session( + credentials_file=None, + service_account=None, + gcp_credentials=None, + service_account_key=None, + ) + + assert isinstance(session, TokenCredentials) + assert session.token == access_token + assert project_id == default_project_id + def test_setup_session_with_organization_id(self): mocked_credentials = MagicMock() From 23b65c7728a1e648852087618a24e4c0b3296a39 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 16 Apr 2025 17:13:55 +0200 Subject: [PATCH 172/359] feat(teams): add new check `teams_email_sending_to_channel_disabled` (#7533) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ..._sending_to_channel_disabled.metadata.json | 30 +++++ ...teams_email_sending_to_channel_disabled.py | 41 +++++++ .../m365/services/teams/teams_service.py | 7 +- ..._email_sending_to_channel_disabled_test.py | 105 ++++++++++++++++++ 6 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index a3edc2e94a..9a73fdf02f 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) +- Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.metadata.json new file mode 100644 index 0000000000..ddee3091c7 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_email_sending_to_channel_disabled", + "CheckTitle": "Ensure users are not be able to email the channel directly.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Settings", + "Description": "Ensure users can not send emails to channel email addresses.", + "Risk": "Allowing users to send emails to Teams channel email addresses introduces a security risk, as these addresses are outside the tenant’s domain and lack proper security controls. This creates a potential attack vector where threat actors could exploit the channel email to deliver malicious content or spam.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/get-csteamsclientconfiguration?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsClientConfiguration -Identity Global -AllowEmailIntoChannel $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Teams select Teams settings. 3. Under email integration set Users can send emails to a channel email address to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable the ability for users to send emails to Teams channel email addresses to reduce the risk of external abuse and enhance control over organizational communications.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/get-csteamsclientconfiguration?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py new file mode 100644 index 0000000000..f5a96266c3 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py @@ -0,0 +1,41 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_email_sending_to_channel_disabled(Check): + """Check if + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for + + This method checks if + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + teams_settings = teams_client.teams_settings + report = CheckReportM365( + metadata=self.metadata(), + resource=teams_settings if teams_settings else {}, + resource_name="Teams Settings", + resource_id="teamsSettings", + ) + report.status = "FAIL" + report.status_extended = "Users can send emails to channel email addresses." + + if teams_settings and not teams_settings.allow_email_into_channel: + report.status = "PASS" + report.status_extended = ( + "Users can not send emails to channel email addresses." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 1415b6118b..71474ce724 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -14,8 +14,9 @@ class Teams(M365Service): def _get_teams_client_configuration(self): logger.info("M365 - Getting Teams settings...") - settings = self.powershell.get_teams_settings() + teams_settings = None try: + settings = self.powershell.get_teams_settings() teams_settings = TeamsSettings( cloud_storage_settings=CloudStorageSettings( allow_box=settings.get("AllowBox", True), @@ -23,7 +24,8 @@ class Teams(M365Service): allow_egnyte=settings.get("AllowEgnyte", True), allow_google_drive=settings.get("AllowGoogleDrive", True), allow_share_file=settings.get("AllowShareFile", True), - ) + ), + allow_email_into_channel=settings.get("AllowEmailIntoChannel", True), ) except Exception as error: @@ -43,3 +45,4 @@ class CloudStorageSettings(BaseModel): class TeamsSettings(BaseModel): cloud_storage_settings: CloudStorageSettings + allow_email_into_channel: bool = True diff --git a/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py b/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py new file mode 100644 index 0000000000..7ee0a6a61d --- /dev/null +++ b/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py @@ -0,0 +1,105 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_email_sending_to_channel_disabled: + def test_email_sending_to_channel_no_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_email_sending_to_channel_disabled.teams_email_sending_to_channel_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_email_sending_to_channel_disabled.teams_email_sending_to_channel_disabled import ( + teams_email_sending_to_channel_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + CloudStorageSettings, + TeamsSettings, + ) + + teams_client.teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=True, + allow_drop_box=True, + allow_egnyte=True, + allow_google_drive=True, + allow_share_file=True, + ), + allow_email_into_channel=True, + ) + + check = teams_email_sending_to_channel_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Users can send emails to channel email addresses." + ) + assert result[0].resource == teams_client.teams_settings.dict() + assert result[0].resource_name == "Teams Settings" + assert result[0].resource_id == "teamsSettings" + assert result[0].location == "global" + + def test_email_sending_to_channel_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_email_sending_to_channel_disabled.teams_email_sending_to_channel_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_email_sending_to_channel_disabled.teams_email_sending_to_channel_disabled import ( + teams_email_sending_to_channel_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + CloudStorageSettings, + TeamsSettings, + ) + + teams_client.teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=True, + allow_drop_box=True, + allow_egnyte=True, + allow_google_drive=True, + allow_share_file=True, + ), + allow_email_into_channel=False, + ) + + check = teams_email_sending_to_channel_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Users can not send emails to channel email addresses." + ) + assert result[0].resource == teams_client.teams_settings.dict() + assert result[0].resource_name == "Teams Settings" + assert result[0].resource_id == "teamsSettings" + assert result[0].location == "global" From 7d0e94eecb54251eb97389009357862651a41401 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 16 Apr 2025 18:19:06 +0200 Subject: [PATCH 173/359] feat(exchange): add service and new check `exchange_organization_mailbox_auditing_enabled` (#7408) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 19 +++ .../m365/services/exchange/__init__.py | 0 .../m365/services/exchange/exchange_client.py | 4 + .../__init__.py | 0 ...ion_mailbox_auditing_enabled.metadata.json | 30 +++++ ...e_organization_mailbox_auditing_enabled.py | 44 +++++++ .../services/exchange/exchange_service.py | 35 ++++++ ...anization_mailbox_auditing_enabled_test.py | 116 ++++++++++++++++++ .../exchange/exchange_service_test.py | 52 ++++++++ 10 files changed, 301 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_client.py create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.py create mode 100644 prowler/providers/m365/services/exchange/exchange_service.py create mode 100644 tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py create mode 100644 tests/providers/m365/services/exchange/exchange_service_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9a73fdf02f..aeb3470893 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) +- Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 367b1fe2af..de3de2393f 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -169,3 +169,22 @@ class M365PowerShell(PowerShellSession): return self.execute( "Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json" ) + + def get_organization_config(self) -> dict: + """ + Get Exchange Online Organization Configuration. + + Retrieves the current Exchange Online organization configuration settings. + + Returns: + dict: Organization configuration settings in JSON format. + + Example: + >>> get_organization_config() + { + "Name": "MyOrganization", + "Guid": "12345678-1234-1234-1234-123456789012" + "AuditDisabled": false + } + """ + return self.execute("Get-OrganizationConfig | ConvertTo-Json") diff --git a/prowler/providers/m365/services/exchange/__init__.py b/prowler/providers/m365/services/exchange/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_client.py b/prowler/providers/m365/services/exchange/exchange_client.py new file mode 100644 index 0000000000..5be172a2a3 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.m365.services.exchange.exchange_service import Exchange + +exchange_client = Exchange(Provider.get_global_provider()) diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.metadata.json new file mode 100644 index 0000000000..abe968f4e0 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_organization_mailbox_auditing_enabled", + "CheckTitle": "Ensure AuditDisabled organizationally is set to False.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Organization Configuration", + "Description": "Ensure that the AuditDisabled property is set to False at the organizational level in Exchange Online. This enables mailbox auditing by default for all mailboxes and overrides individual mailbox settings.", + "Risk": "If mailbox auditing is disabled at the organization level, no mailbox actions are audited, limiting forensic investigation capabilities and exposing the organization to undetected malicious activity.", + "RelatedUrl": "https://learn.microsoft.com/en-us/purview/audit-mailboxes?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "Set-OrganizationConfig -AuditDisabled $false", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Set AuditDisabled to False at the organization level to ensure mailbox auditing is always enforced.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-organizationconfig?view=exchange-ps#-auditdisabled" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.py b/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.py new file mode 100644 index 0000000000..2e4cdaedea --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled.py @@ -0,0 +1,44 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_organization_mailbox_auditing_enabled(Check): + """Check if Exchange mailbox auditing is enabled. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for Exchange mailbox auditing. + + This method checks if mailbox auditing is enabled in the Exchange organization configuration. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + organization_config = exchange_client.organization_config + if organization_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=organization_config, + resource_name=organization_config.name, + resource_id=organization_config.guid, + ) + report.status = "FAIL" + report.status_extended = ( + "Exchange mailbox auditing is not enabled on your organization." + ) + + if not organization_config.audit_disabled: + report.status = "PASS" + report.status_extended = ( + "Exchange mailbox auditing is enabled on your organization." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py new file mode 100644 index 0000000000..5ae7171882 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -0,0 +1,35 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider + + +class Exchange(M365Service): + def __init__(self, provider: M365Provider): + super().__init__(provider) + self.powershell.connect_exchange_online() + self.organization_config = self._get_organization_config() + self.powershell.close() + + def _get_organization_config(self): + logger.info("Microsoft365 - Getting Exchange Organization configuration...") + organization_config = None + try: + organization_configuration = self.powershell.get_organization_config() + organization_config = Organization( + name=organization_configuration.get("Name", ""), + guid=organization_configuration.get("Guid", ""), + audit_disabled=organization_configuration.get("AuditDisabled", False), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return organization_config + + +class Organization(BaseModel): + name: str + guid: str + audit_disabled: bool diff --git a/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py new file mode 100644 index 0000000000..104b050541 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py @@ -0,0 +1,116 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_organization_mailbox_auditing_enabled: + def test_no_organization(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.organization_config = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled import ( + exchange_organization_mailbox_auditing_enabled, + ) + + check = exchange_organization_mailbox_auditing_enabled() + result = check.execute() + assert len(result) == 0 + + def test_audit_log_search_disabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled import ( + exchange_organization_mailbox_auditing_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.organization_config = Organization( + audit_disabled=True, name="test", guid="test" + ) + + check = exchange_organization_mailbox_auditing_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Exchange mailbox auditing is not enabled on your organization." + ) + assert result[0].resource == exchange_client.organization_config.dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" + + def test_audit_log_search_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailbox_auditing_enabled.exchange_organization_mailbox_auditing_enabled import ( + exchange_organization_mailbox_auditing_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.organization_config = Organization( + audit_disabled=False, name="test", guid="test" + ) + + check = exchange_organization_mailbox_auditing_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Exchange mailbox auditing is enabled on your organization." + ) + assert result[0].resource == exchange_client.organization_config.dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py new file mode 100644 index 0000000000..92cd275365 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -0,0 +1,52 @@ +from unittest import mock +from unittest.mock import patch + +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.exchange.exchange_service import ( + Exchange, + Organization, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +def mock_exchange_get_organization_config(_): + return Organization(audit_disabled=True, name="test", guid="test") + + +class Test_Exchange_Service: + def test_get_client(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert exchange_client.client.__class__.__name__ == "GraphServiceClient" + assert exchange_client.powershell.__class__.__name__ == "M365PowerShell" + exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_organization_config", + new=mock_exchange_get_organization_config, + ) + def test_get_organization_config(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + organization_config = exchange_client.organization_config + assert organization_config.name == "test" + assert organization_config.guid == "test" + assert organization_config.audit_disabled is True + + exchange_client.powershell.close() From abae5f1626f3c1ccfd5e73fb8d2a83186a9d0940 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 16 Apr 2025 20:06:32 +0200 Subject: [PATCH 174/359] feat(exchange): add new check `exchange_mailbox_audit_bypass_disabled` (#7418) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 19 ++ .../admincenter/admincenter_service.py | 15 -- .../__init__.py | 0 ...ailbox_audit_bypass_disabled.metadata.json | 30 +++ .../exchange_mailbox_audit_bypass_disabled.py | 39 ++++ .../services/exchange/exchange_service.py | 41 +++- .../purview_audit_log_search_enabled.py | 29 +-- .../m365/services/purview/purview_service.py | 9 +- ...teams_email_sending_to_channel_disabled.py | 29 +-- .../teams_external_file_sharing_restricted.py | 77 ++++---- .../m365/services/teams/teams_service.py | 23 ++- ...ange_mailbox_audit_bypass_disabled_test.py | 175 ++++++++++++++++++ .../exchange/exchange_service_test.py | 34 ++++ 14 files changed, 421 insertions(+), 100 deletions(-) create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index aeb3470893..d433490787 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. - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) +- Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index de3de2393f..fd982750af 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -188,3 +188,22 @@ class M365PowerShell(PowerShellSession): } """ return self.execute("Get-OrganizationConfig | ConvertTo-Json") + + def get_mailbox_audit_config(self) -> dict: + """ + Get Exchange Online Mailbox Audit Configuration. + + Retrieves the current mailbox audit configuration settings for Exchange Online. + + Returns: + dict: Mailbox audit configuration settings in JSON format. + + Example: + >>> get_mailbox_audit_config() + { + "Name": "MyMailbox", + "Id": "12345678-1234-1234-1234-123456789012", + "AuditBypassEnabled": false + } + """ + return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") diff --git a/prowler/providers/m365/services/admincenter/admincenter_service.py b/prowler/providers/m365/services/admincenter/admincenter_service.py index 723c7644d1..ed8e4ad4a2 100644 --- a/prowler/providers/m365/services/admincenter/admincenter_service.py +++ b/prowler/providers/m365/services/admincenter/admincenter_service.py @@ -1,7 +1,6 @@ from asyncio import gather, get_event_loop from typing import List, Optional -from msgraph.generated.models.o_data_errors.o_data_error import ODataError from pydantic import BaseModel from prowler.lib.logger import logger @@ -40,20 +39,6 @@ class AdminCenter(M365Service): license_details = await self.client.users.by_user_id( user.id ).license_details.get() - try: - mailbox_settings = await self.client.users.by_user_id( - user.id - ).mailbox_settings.get() - mailbox_settings.user_purpose - except ODataError as error: - if error.error.code == "MailboxNotEnabledForRESTAPI": - logger.warning( - f"MailboxNotEnabledForRESTAPI for user {user.id}" - ) - else: - logger.error( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) users.update( { user.id: User( diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.metadata.json new file mode 100644 index 0000000000..b3dcd6491f --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_mailbox_audit_bypass_disabled", + "CheckTitle": "Ensure 'AuditBypassEnabled' is not enabled on any mailbox in the organization.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Mailboxes", + "Description": "Ensure that no mailboxes in the organization have 'AuditBypassEnabled' set to true. This setting prevents mailbox audit logging and can allow unauthorized access without traceability.", + "Risk": "If 'AuditBypassEnabled' is set to true for any mailbox, access to those mailboxes won't be logged, creating a blind spot in forensic analysis and increasing the risk of undetected malicious activity.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/exchange/get-mailboxauditbypassassociation?view=exchange-ps", + "Remediation": { + "Code": { + "CLI": "$MBXAudit = Get-MailboxAuditBypassAssociation -ResultSize unlimited | Where-Object { $_.AuditBypassEnabled -eq $true }; foreach ($mailbox in $MBXAudit) { $mailboxName = $mailbox.Name; Set-MailboxAuditBypassAssociation -Identity $mailboxName -AuditBypassEnabled $false; Write-Host \"Audit Bypass disabled for mailbox Identity: $mailboxName\" -ForegroundColor Green }", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that no mailboxes have 'AuditBypassEnabled' enabled to guarantee full audit logging for all mailbox activities.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-mailboxauditbypassassociation?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.py b/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.py new file mode 100644 index 0000000000..449c8f3ac3 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled.py @@ -0,0 +1,39 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_mailbox_audit_bypass_disabled(Check): + """Verify if Exchange mailbox auditing is enabled. + + This check ensures that mailbox auditing is not bypassed and is properly enabled. + """ + + def execute(self) -> List[CheckReportM365]: + """Run the check to validate Exchange mailbox auditing. + + Iterates through the mailbox configurations to determine if auditing is enabled + and generates a report for each mailbox. + + Returns: + List[CheckReportM365]: A list of reports with the audit status for each mailbox. + """ + findings = [] + for mailbox_config in exchange_client.mailboxes_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=mailbox_config, + resource_name=mailbox_config.name, + resource_id=mailbox_config.id, + ) + report.status = "FAIL" + report.status_extended = f"Exchange mailbox auditing is bypassed and not enabled for mailbox: {mailbox_config.name}." + + if not mailbox_config.audit_bypass_enabled: + report.status = "PASS" + report.status_extended = f"Exchange mailbox auditing is enabled for mailbox: {mailbox_config.name}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 5ae7171882..f369edb6b5 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -10,6 +10,7 @@ class Exchange(M365Service): super().__init__(provider) self.powershell.connect_exchange_online() self.organization_config = self._get_organization_config() + self.mailboxes_config = self._get_mailbox_audit_config() self.powershell.close() def _get_organization_config(self): @@ -17,19 +18,49 @@ class Exchange(M365Service): organization_config = None try: organization_configuration = self.powershell.get_organization_config() - organization_config = Organization( - name=organization_configuration.get("Name", ""), - guid=organization_configuration.get("Guid", ""), - audit_disabled=organization_configuration.get("AuditDisabled", False), - ) + if organization_configuration: + organization_config = Organization( + name=organization_configuration.get("Name", ""), + guid=organization_configuration.get("Guid", ""), + audit_disabled=organization_configuration.get( + "AuditDisabled", False + ), + ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) return organization_config + def _get_mailbox_audit_config(self): + logger.info("Microsoft365 - Getting mailbox audit configuration...") + mailboxes_config = [] + try: + mailbox_audit_data = self.powershell.get_mailbox_audit_config() + for mailbox_audit_config in mailbox_audit_data: + mailboxes_config.append( + MailboxAuditConfig( + name=mailbox_audit_config.get("Name", ""), + id=mailbox_audit_config.get("Id", ""), + audit_bypass_enabled=mailbox_audit_config.get( + "AuditBypassEnabled", True + ), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return mailboxes_config + class Organization(BaseModel): name: str guid: str audit_disabled: bool + + +class MailboxAuditConfig(BaseModel): + name: str + id: str + audit_bypass_enabled: bool diff --git a/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py index f6884dbfcf..49df75ec93 100644 --- a/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py +++ b/prowler/providers/m365/services/purview/purview_audit_log_search_enabled/purview_audit_log_search_enabled.py @@ -21,21 +21,22 @@ class purview_audit_log_search_enabled(Check): """ findings = [] audit_log_config = purview_client.audit_log_config - report = CheckReportM365( - metadata=self.metadata(), - resource=audit_log_config if audit_log_config else {}, - resource_name="Purview Settings", - resource_id="purviewSettings", - ) - report.status = "FAIL" - report.status_extended = "Purview audit log search is not enabled." + if audit_log_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=audit_log_config if audit_log_config else {}, + resource_name="Purview Settings", + resource_id="purviewSettings", + ) + report.status = "FAIL" + report.status_extended = "Purview audit log search is not enabled." - if purview_client.audit_log_config and getattr( - purview_client.audit_log_config, "audit_log_search", False - ): - report.status = "PASS" - report.status_extended = "Purview audit log search is enabled." + if purview_client.audit_log_config and getattr( + purview_client.audit_log_config, "audit_log_search", False + ): + report.status = "PASS" + report.status_extended = "Purview audit log search is enabled." - findings.append(report) + findings.append(report) return findings diff --git a/prowler/providers/m365/services/purview/purview_service.py b/prowler/providers/m365/services/purview/purview_service.py index 5d6fdfce36..2323b28dce 100644 --- a/prowler/providers/m365/services/purview/purview_service.py +++ b/prowler/providers/m365/services/purview/purview_service.py @@ -17,11 +17,12 @@ class Purview(M365Service): audit_log_config = None try: audit_log_config_response = self.powershell.get_audit_log_config() - audit_log_config = AuditLogConfig( - audit_log_search=audit_log_config_response.get( - "UnifiedAuditLogIngestionEnabled", False + if audit_log_config_response: + audit_log_config = AuditLogConfig( + audit_log_search=audit_log_config_response.get( + "UnifiedAuditLogIngestionEnabled", False + ) ) - ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py index f5a96266c3..bcf4eec9b8 100644 --- a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py +++ b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py @@ -21,21 +21,22 @@ class teams_email_sending_to_channel_disabled(Check): """ findings = [] teams_settings = teams_client.teams_settings - report = CheckReportM365( - metadata=self.metadata(), - resource=teams_settings if teams_settings else {}, - resource_name="Teams Settings", - resource_id="teamsSettings", - ) - report.status = "FAIL" - report.status_extended = "Users can send emails to channel email addresses." - - if teams_settings and not teams_settings.allow_email_into_channel: - report.status = "PASS" - report.status_extended = ( - "Users can not send emails to channel email addresses." + if teams_settings: + report = CheckReportM365( + metadata=self.metadata(), + resource=teams_settings if teams_settings else {}, + resource_name="Teams Settings", + resource_id="teamsSettings", ) + report.status = "FAIL" + report.status_extended = "Users can send emails to channel email addresses." - findings.append(report) + if teams_settings and not teams_settings.allow_email_into_channel: + report.status = "PASS" + report.status_extended = ( + "Users can not send emails to channel email addresses." + ) + + findings.append(report) return findings diff --git a/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py index 2ec8cc87f8..33111d5509 100644 --- a/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py +++ b/prowler/providers/m365/services/teams/teams_external_file_sharing_restricted/teams_external_file_sharing_restricted.py @@ -22,46 +22,47 @@ class teams_external_file_sharing_restricted(Check): List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - cloud_storage_settings = teams_client.teams_settings.cloud_storage_settings - report = CheckReportM365( - metadata=self.metadata(), - resource=cloud_storage_settings if cloud_storage_settings else {}, - resource_name="Cloud Storage Settings", - resource_id="cloudStorageSettings", - ) - report.status = "FAIL" - report.status_extended = "External file sharing is not restricted to only approved cloud storage services." + if teams_client.teams_settings: + cloud_storage_settings = teams_client.teams_settings.cloud_storage_settings + report = CheckReportM365( + metadata=self.metadata(), + resource=cloud_storage_settings if cloud_storage_settings else {}, + resource_name="Cloud Storage Settings", + resource_id="cloudStorageSettings", + ) + report.status = "FAIL" + report.status_extended = "External file sharing is not restricted to only approved cloud storage services." - allowed_services = teams_client.audit_config.get( - "allowed_cloud_storage_services", [] - ) - if cloud_storage_settings: - # Get storage services from CloudStorageSettings class items - storage_services = [ - attr - for attr, type in CloudStorageSettings.__annotations__.items() - if type is bool - ] + allowed_services = teams_client.audit_config.get( + "allowed_cloud_storage_services", [] + ) + if cloud_storage_settings: + # Get storage services from CloudStorageSettings class items + storage_services = [ + attr + for attr, type in CloudStorageSettings.__annotations__.items() + if type is bool + ] - # Check if all services are disabled when no allowed services are specified - # or if all enabled services are in the allowed list - if ( - not allowed_services - and all( - not getattr(cloud_storage_settings, service, True) - for service in storage_services - ) - ) or ( - allowed_services - and not any( - getattr(cloud_storage_settings, service, True) - and service not in allowed_services - for service in storage_services - ) - ): - report.status = "PASS" - report.status_extended = "External file sharing is restricted to only approved cloud storage services." + # Check if all services are disabled when no allowed services are specified + # or if all enabled services are in the allowed list + if ( + not allowed_services + and all( + not getattr(cloud_storage_settings, service, True) + for service in storage_services + ) + ) or ( + allowed_services + and not any( + getattr(cloud_storage_settings, service, True) + and service not in allowed_services + for service in storage_services + ) + ): + report.status = "PASS" + report.status_extended = "External file sharing is restricted to only approved cloud storage services." - findings.append(report) + findings.append(report) return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 71474ce724..1fb71c7740 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -17,16 +17,19 @@ class Teams(M365Service): teams_settings = None try: settings = self.powershell.get_teams_settings() - teams_settings = TeamsSettings( - cloud_storage_settings=CloudStorageSettings( - allow_box=settings.get("AllowBox", True), - allow_drop_box=settings.get("AllowDropBox", True), - allow_egnyte=settings.get("AllowEgnyte", True), - allow_google_drive=settings.get("AllowGoogleDrive", True), - allow_share_file=settings.get("AllowShareFile", True), - ), - allow_email_into_channel=settings.get("AllowEmailIntoChannel", True), - ) + if settings: + teams_settings = TeamsSettings( + cloud_storage_settings=CloudStorageSettings( + allow_box=settings.get("AllowBox", True), + allow_drop_box=settings.get("AllowDropBox", True), + allow_egnyte=settings.get("AllowEgnyte", True), + allow_google_drive=settings.get("AllowGoogleDrive", True), + allow_share_file=settings.get("AllowShareFile", True), + ), + allow_email_into_channel=settings.get( + "AllowEmailIntoChannel", True + ), + ) except Exception as error: logger.error( diff --git a/tests/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled_test.py b/tests/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled_test.py new file mode 100644 index 0000000000..66ec06945a --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_mailbox_audit_bypass_disabled/exchange_mailbox_audit_bypass_disabled_test.py @@ -0,0 +1,175 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_mailbox_audit_bypass_disabled: + def test_no_mailboxes(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.mailboxes_config = [] + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled import ( + exchange_mailbox_audit_bypass_disabled, + ) + + check = exchange_mailbox_audit_bypass_disabled() + result = check.execute() + assert len(result) == 0 + + def test_audit_bypass_disabled_and_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled import ( + exchange_mailbox_audit_bypass_disabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + MailboxAuditConfig, + ) + + exchange_client.mailboxes_config = [ + MailboxAuditConfig(name="test", id="test", audit_bypass_enabled=True), + MailboxAuditConfig( + name="test2", id="test2", audit_bypass_enabled=False + ), + ] + + check = exchange_mailbox_audit_bypass_disabled() + result = check.execute() + + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Exchange mailbox auditing is bypassed and not enabled for mailbox: test." + ) + assert result[0].resource == exchange_client.mailboxes_config[0].dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Exchange mailbox auditing is enabled for mailbox: test2." + ) + assert result[1].resource == exchange_client.mailboxes_config[1].dict() + assert result[1].resource_name == "test2" + assert result[1].resource_id == "test2" + assert result[1].location == "global" + + def test_audit_bypass_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled import ( + exchange_mailbox_audit_bypass_disabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + MailboxAuditConfig, + ) + + exchange_client.mailboxes_config = [ + MailboxAuditConfig(name="test", id="test", audit_bypass_enabled=True), + ] + + check = exchange_mailbox_audit_bypass_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Exchange mailbox auditing is bypassed and not enabled for mailbox: test." + ) + assert result[0].resource == exchange_client.mailboxes_config[0].dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" + + def test_audit_bypass_disabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_audit_bypass_disabled.exchange_mailbox_audit_bypass_disabled import ( + exchange_mailbox_audit_bypass_disabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + MailboxAuditConfig, + ) + + exchange_client.mailboxes_config = [ + MailboxAuditConfig(name="test", id="test", audit_bypass_enabled=False), + ] + + check = exchange_mailbox_audit_bypass_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Exchange mailbox auditing is enabled for mailbox: test." + ) + assert result[0].resource == exchange_client.mailboxes_config[0].dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 92cd275365..83e1af83a5 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -4,6 +4,7 @@ from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, + MailboxAuditConfig, Organization, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -13,6 +14,13 @@ def mock_exchange_get_organization_config(_): return Organization(audit_disabled=True, name="test", guid="test") +def mock_exchange_get_mailbox_audit_config(_): + return [ + MailboxAuditConfig(name="test", id="test", audit_bypass_enabled=False), + MailboxAuditConfig(name="test2", id="test2", audit_bypass_enabled=True), + ] + + class Test_Exchange_Service: def test_get_client(self): with ( @@ -50,3 +58,29 @@ class Test_Exchange_Service: assert organization_config.audit_disabled is True exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_mailbox_audit_config", + new=mock_exchange_get_mailbox_audit_config, + ) + def test_get_mailbox_audit_config(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + mailbox_audit_config = exchange_client.mailboxes_config + assert len(mailbox_audit_config) == 2 + assert mailbox_audit_config[0].name == "test" + assert mailbox_audit_config[0].id == "test" + assert mailbox_audit_config[0].audit_bypass_enabled is False + assert mailbox_audit_config[1].name == "test2" + assert mailbox_audit_config[1].id == "test2" + assert mailbox_audit_config[1].audit_bypass_enabled is True + + exchange_client.powershell.close() From 56d7431d5675c5dfc109c9c9845fc690da06dcd3 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 17 Apr 2025 19:33:43 +0200 Subject: [PATCH 175/359] feat(defender): add service and new check `defender_malware_policy_common_attachments_filter_enabled` (#7425) Co-authored-by: HugoPBrito Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 3 +- .../m365/lib/powershell/m365_powershell.py | 18 +++ .../m365/services/defender/__init__.py | 0 .../m365/services/defender/defender_client.py | 4 + .../__init__.py | 0 ...n_attachments_filter_enabled.metadata.json | 30 ++++ ...olicy_common_attachments_filter_enabled.py | 42 ++++++ .../services/defender/defender_service.py | 38 +++++ ..._common_attachments_filter_enabled_test.py | 141 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 54 +++++++ 10 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/m365/services/defender/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_client.py create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py create mode 100644 prowler/providers/m365/services/defender/defender_service.py create mode 100644 tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py create mode 100644 tests/providers/m365/services/defender/m365_defender_service_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index d433490787..9b1b32b069 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,8 +8,9 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). +- Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331). +- Add service Defender to Microsoft365 with one check for Common Attachments filter enabled in Malware Policies [(#7425)](https://github.com/prowler-cloud/prowler/pull/7425). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). -- Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index fd982750af..838d85311d 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -170,6 +170,24 @@ class M365PowerShell(PowerShellSession): "Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json" ) + def get_malware_filter_policy(self) -> dict: + """ + Get Defender Malware Filter Policy. + + Retrieves the current Defender anti-malware filter policy settings. + + Returns: + dict: Malware filter policy settings in JSON format. + + Example: + >>> get_malware_filter_policy() + { + "EnableFileFilter": true, + "Identity": "Default" + } + """ + return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json") + def get_organization_config(self) -> dict: """ Get Exchange Online Organization Configuration. diff --git a/prowler/providers/m365/services/defender/__init__.py b/prowler/providers/m365/services/defender/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_client.py b/prowler/providers/m365/services/defender/defender_client.py new file mode 100644 index 0000000000..b9445c5aa7 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.m365.services.defender.defender_service import Defender + +defender_client = Defender(Provider.get_global_provider()) diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/__init__.py b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.metadata.json b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.metadata.json new file mode 100644 index 0000000000..634236b38d --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_malware_policy_common_attachments_filter_enabled", + "CheckTitle": "Ensure the Common Attachment Types Filter is enabled.", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Defender Malware Policy", + "Description": "Ensure that the Common Attachment Types Filter is enabled in anti-malware policies to block known and custom malicious file types from being attached to emails.", + "Risk": "If this setting is not enabled, users may receive emails with malicious attachments that could contain malware, increasing the risk of endpoint infection or data compromise.", + "RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/anti-malware-policies-configure?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "Set-MalwareFilterPolicy -Identity Default -EnableFileFilter $true", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules. 3. On the Policies & rules page select Threat policies. 4. Under Policies, select Anti-malware and click on the Default (Default) policy. 5. On the policy page, scroll to the bottom and click Edit protection settings. 6. Check the option Enable the common attachments filter. 7. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable the common attachment types filter in your default or custom anti-malware policy to prevent the delivery of emails with potentially dangerous attachments.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-malwarefilterpolicy?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py new file mode 100644 index 0000000000..63dc7b93cd --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_malware_policy_common_attachments_filter_enabled(Check): + """ + Check if the Common Attachment Types Filter is enabled in the Defender anti-malware policy. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if the Common Attachment Types Filter is enabled. + + This method checks the Defender anti-malware policy to determine if the + Common Attachment Types Filter is enabled. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Malware Policy", + resource_id="defenderMalwarePolicy", + ) + report.status = "FAIL" + report.status_extended = f"Common Attachment Types Filter is not enabled in the Defender anti-malware policy {policy.identity}." + + if policy.enable_file_filter: + report.status = "PASS" + report.status_extended = f"Common Attachment Types Filter is enabled in the Defender anti-malware policy {policy.identity}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py new file mode 100644 index 0000000000..9d12b224dc --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -0,0 +1,38 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.m365.lib.service.service import M365Service +from prowler.providers.m365.m365_provider import M365Provider + + +class Defender(M365Service): + def __init__(self, provider: M365Provider): + super().__init__(provider) + self.powershell.connect_exchange_online() + self.malware_policies = self._get_malware_filter_policy() + self.powershell.close() + + def _get_malware_filter_policy(self): + logger.info("M365 - Getting Defender malware filter policy...") + malware_policies = [] + try: + malware_policy = self.powershell.get_malware_filter_policy() + if isinstance(malware_policy, dict): + malware_policy = [malware_policy] + for policy in malware_policy: + malware_policies.append( + DefenderMalwarePolicy( + enable_file_filter=policy.get("EnableFileFilter", True), + identity=policy.get("Identity", ""), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return malware_policies + + +class DefenderMalwarePolicy(BaseModel): + enable_file_filter: bool + identity: str diff --git a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py new file mode 100644 index 0000000000..3a4aa7aa5c --- /dev/null +++ b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py @@ -0,0 +1,141 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_malware_policy_common_attachments_filter_enabled: + def test_enable_file_filter_disabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderMalwarePolicy, + ) + + defender_client.malware_policies = [ + DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"), + DefenderMalwarePolicy(enable_file_filter=False, identity="Policy2"), + ] + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy1." + ) + assert result[0].resource == defender_client.malware_policies[0].dict() + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy2." + ) + assert result[1].resource == defender_client.malware_policies[1].dict() + assert result[1].resource_name == "Defender Malware Policy" + assert result[1].resource_id == "defenderMalwarePolicy" + assert result[1].location == "global" + + def test_enable_file_filter_enabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderMalwarePolicy, + ) + + defender_client.malware_policies = [ + DefenderMalwarePolicy(enable_file_filter=True, identity="Policy1"), + DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"), + ] + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy1." + ) + assert result[0].resource == defender_client.malware_policies[0].dict() + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy2." + ) + assert result[1].resource == defender_client.malware_policies[1].dict() + assert result[1].resource_name == "Defender Malware Policy" + assert result[1].resource_id == "defenderMalwarePolicy" + assert result[1].location == "global" + + def test_no_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + + defender_client.malware_policies = [] + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py new file mode 100644 index 0000000000..f800f9dfb3 --- /dev/null +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -0,0 +1,54 @@ +from unittest import mock +from unittest.mock import patch + +from prowler.providers.m365.models import M365IdentityInfo +from prowler.providers.m365.services.defender.defender_service import ( + Defender, + DefenderMalwarePolicy, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +def mock_defender_get_malware_filter_policy(_): + return [ + DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"), + DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"), + ] + + +class Test_Defender_Service: + def test_get_client(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert defender_client.client.__class__.__name__ == "GraphServiceClient" + assert defender_client.powershell.__class__.__name__ == "M365PowerShell" + defender_client.powershell.close() + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_malware_filter_policy", + new=mock_defender_get_malware_filter_policy, + ) + def test__get_malware_filter_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + malware_policies = defender_client.malware_policies + assert malware_policies[0].enable_file_filter is False + assert malware_policies[0].identity == "Policy1" + assert malware_policies[1].enable_file_filter is True + assert malware_policies[1].identity == "Policy2" From d09a680aaa1058e890f11d25b34eadedb4ba2296 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:08:05 +0200 Subject: [PATCH 176/359] feat(defender): add new check `defender_malware_policy_notifications_internal_users_malware_enabled` (#7435) Co-authored-by: HugoPBrito Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + ...olicy_common_attachments_filter_enabled.py | 24 ++- .../__init__.py | 0 ...ternal_users_malware_enabled.metadata.json | 30 ++++ ...ications_internal_users_malware_enabled.py | 62 +++++++ .../services/defender/defender_service.py | 19 ++- ..._common_attachments_filter_enabled_test.py | 55 +++---- ...ons_internal_users_malware_enabled_test.py | 155 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 25 ++- 9 files changed, 329 insertions(+), 42 deletions(-) create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py create mode 100644 tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9b1b32b069..af54d34cc5 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331). - Add service Defender to Microsoft365 with one check for Common Attachments filter enabled in Malware Policies [(#7425)](https://github.com/prowler-cloud/prowler/pull/7425). +- Add check for Notifications for Internal users enabled in Malware Policies from service Defender in M365 [(#7435)](https://github.com/prowler-cloud/prowler/pull/7435). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py index 63dc7b93cd..75c9707d26 100644 --- a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py +++ b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py @@ -23,19 +23,31 @@ class defender_malware_policy_common_attachments_filter_enabled(Check): List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - for policy in defender_client.malware_policies: + if not defender_client.malware_policies: report = CheckReportM365( metadata=self.metadata(), - resource=policy, + resource={}, resource_name="Defender Malware Policy", resource_id="defenderMalwarePolicy", ) report.status = "FAIL" - report.status_extended = f"Common Attachment Types Filter is not enabled in the Defender anti-malware policy {policy.identity}." + report.status_extended = "Common Attachment Types Filter is not enabled." + findings.append(report) + else: + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Malware Policy", + resource_id="defenderMalwarePolicy", + ) + report.status = "FAIL" + report.status_extended = f"Common Attachment Types Filter is not enabled in anti-malware policy {policy.identity}." - if policy.enable_file_filter: - report.status = "PASS" - report.status_extended = f"Common Attachment Types Filter is enabled in the Defender anti-malware policy {policy.identity}." + if policy.enable_file_filter: + report.status = "PASS" + report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}." + break findings.append(report) diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/__init__.py b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.metadata.json b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.metadata.json new file mode 100644 index 0000000000..b4d814046a --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_malware_policy_notifications_internal_users_malware_enabled", + "CheckTitle": "Ensure notifications for internal users sending malware is Enabled", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Defender Malware Policy", + "Description": "Verify that Exchange Online Protection (EOP) is configured to notify admins of malicious activity from internal users.", + "Risk": "If notifications for internal users sending malware are not enabled, administrators may not be aware of potential threats originating from within the organization, increasing the risk of undetected malicious activities.", + "RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/anti-malware-protection-about", + "Remediation": { + "Code": { + "CLI": "Set-MalwareFilterPolicy -Identity Default -EnableInternalSenderAdminNotifications $true -InternalSenderAdminAddress 'admin@example.com'", + "NativeIaC": "", + "Other": "1. Connect to Exchange Online using Connect-ExchangeOnline. 2. Execute the command: Get-MalwareFilterPolicy | fl Identity, EnableInternalSenderAdminNotifications, InternalSenderAdminAddress. 3. Ensure 'Notify an admin about undelivered messages from internal senders' is set to On and that at least one email address is listed under Administrator email address.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable notifications for internal users sending malware in your Defender Malware Policy to ensure admins are alerted of potential threats.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-malwarefilterpolicy?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py new file mode 100644 index 0000000000..6eaf933c6a --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py @@ -0,0 +1,62 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_malware_policy_notifications_internal_users_malware_enabled(Check): + """ + Check if notifications for internal users sending malware are enabled in the Defender anti-malware policy. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if notifications for internal users sending malware are enabled. + + This method checks the Defender anti-malware policy to determine if notifications for internal users + sending malware are enabled. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + if not defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource={}, + resource_name="Defender Malware Policy", + resource_id="defenderMalwarePolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "Notifications for internal users sending malware are not enabled." + ) + findings.append(report) + else: + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Malware Policy", + resource_id="defenderMalwarePolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "Notifications for internal users sending malware are not enabled." + ) + + if policy.enable_internal_sender_admin_notifications: + if policy.internal_sender_admin_address: + report.status = "PASS" + report.status_extended = "Notifications for internal users sending malware are enabled." + break + else: + report.status = "FAIL" + report.status_extended = "Notifications for internal users sending malware are enabled, but no email addresses are configured." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 9d12b224dc..3ad098d0b5 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -20,12 +20,19 @@ class Defender(M365Service): if isinstance(malware_policy, dict): malware_policy = [malware_policy] for policy in malware_policy: - malware_policies.append( - DefenderMalwarePolicy( - enable_file_filter=policy.get("EnableFileFilter", True), - identity=policy.get("Identity", ""), + if policy: + malware_policies.append( + DefenderMalwarePolicy( + enable_file_filter=policy.get("EnableFileFilter", True), + identity=policy.get("Identity", ""), + enable_internal_sender_admin_notifications=policy.get( + "EnableInternalSenderAdminNotifications", False + ), + internal_sender_admin_address=policy.get( + "InternalSenderAdminAddress", "" + ), + ) ) - ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -36,3 +43,5 @@ class Defender(M365Service): class DefenderMalwarePolicy(BaseModel): enable_file_filter: bool identity: str + enable_internal_sender_admin_notifications: bool + internal_sender_admin_address: str diff --git a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py index 3a4aa7aa5c..1e06abb97b 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py @@ -30,34 +30,28 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: ) defender_client.malware_policies = [ - DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"), - DefenderMalwarePolicy(enable_file_filter=False, identity="Policy2"), + DefenderMalwarePolicy( + enable_file_filter=False, + identity="Policy1", + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + ), ] check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() - assert len(result) == 2 + assert len(result) == 1 assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy1." + == "Common Attachment Types Filter is not enabled in anti-malware policy Policy1." ) assert result[0].resource == defender_client.malware_policies[0].dict() assert result[0].resource_name == "Defender Malware Policy" assert result[0].resource_id == "defenderMalwarePolicy" assert result[0].location == "global" - assert result[1].status == "FAIL" - assert ( - result[1].status_extended - == "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy2." - ) - assert result[1].resource == defender_client.malware_policies[1].dict() - assert result[1].resource_name == "Defender Malware Policy" - assert result[1].resource_id == "defenderMalwarePolicy" - assert result[1].location == "global" - def test_enable_file_filter_enabled(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" @@ -84,34 +78,28 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: ) defender_client.malware_policies = [ - DefenderMalwarePolicy(enable_file_filter=True, identity="Policy1"), - DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"), + DefenderMalwarePolicy( + enable_file_filter=True, + identity="Policy1", + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + ), ] check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() - assert len(result) == 2 + assert len(result) == 1 assert result[0].status == "PASS" assert ( result[0].status_extended - == "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy1." + == "Common Attachment Types Filter is enabled in anti-malware policy Policy1." ) assert result[0].resource == defender_client.malware_policies[0].dict() assert result[0].resource_name == "Defender Malware Policy" assert result[0].resource_id == "defenderMalwarePolicy" assert result[0].location == "global" - assert result[1].status == "PASS" - assert ( - result[1].status_extended - == "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy2." - ) - assert result[1].resource == defender_client.malware_policies[1].dict() - assert result[1].resource_name == "Defender Malware Policy" - assert result[1].resource_id == "defenderMalwarePolicy" - assert result[1].location == "global" - def test_no_policy(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" @@ -138,4 +126,13 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() - assert len(result) == 0 + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Common Attachment Types Filter is not enabled." + ) + assert result[0].resource == {} + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py new file mode 100644 index 0000000000..db84249c10 --- /dev/null +++ b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py @@ -0,0 +1,155 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_malware_policy_notifications_internal_users_malware_enabled: + def test_notifications_disabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderMalwarePolicy, + ) + + defender_client.malware_policies = [ + DefenderMalwarePolicy( + enable_file_filter=True, + identity="Default", + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + ) + ] + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Notifications for internal users sending malware are not enabled." + ) + assert result[0].resource == defender_client.malware_policies[0].dict() + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" + + def test_notifications_enabled_without_email(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderMalwarePolicy, + ) + + defender_client.malware_policies = [ + DefenderMalwarePolicy( + enable_file_filter=True, + identity="Default", + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="", + ) + ] + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Notifications for internal users sending malware are enabled, but no email addresses are configured." + ) + assert result[0].resource == defender_client.malware_policies[0].dict() + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" + + def test_notifications_enabled_with_email(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderMalwarePolicy, + ) + + defender_client.malware_policies = [ + DefenderMalwarePolicy( + enable_file_filter=True, + identity="Default", + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="security@example.com", + ) + ] + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Notifications for internal users sending malware are enabled." + ) + assert result[0].resource == defender_client.malware_policies[0].dict() + assert result[0].resource_name == "Defender Malware Policy" + assert result[0].resource_id == "defenderMalwarePolicy" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index f800f9dfb3..1ef9ff1607 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -11,8 +11,18 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider def mock_defender_get_malware_filter_policy(_): return [ - DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"), - DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"), + DefenderMalwarePolicy( + enable_file_filter=False, + identity="Policy1", + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + ), + DefenderMalwarePolicy( + enable_file_filter=True, + identity="Policy2", + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="security@example.com", + ), ] @@ -50,5 +60,16 @@ class Test_Defender_Service: malware_policies = defender_client.malware_policies assert malware_policies[0].enable_file_filter is False assert malware_policies[0].identity == "Policy1" + assert ( + malware_policies[0].enable_internal_sender_admin_notifications is False + ) + assert malware_policies[0].internal_sender_admin_address == "" assert malware_policies[1].enable_file_filter is True assert malware_policies[1].identity == "Policy2" + assert ( + malware_policies[1].enable_internal_sender_admin_notifications is True + ) + assert ( + malware_policies[1].internal_sender_admin_address + == "security@example.com" + ) From 4f3496194d5741cedcd93d999631350f6c7f8937 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 18 Apr 2025 18:42:19 +0200 Subject: [PATCH 177/359] feat(defender): add new check `defender_antiphishing_policy_configured` (#7453) --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 43 +++ .../__init__.py | 0 ...tiphishing_policy_configured.metadata.json | 30 ++ ...defender_antiphishing_policy_configured.py | 59 ++++ .../services/defender/defender_service.py | 66 ++++ ...der_antiphishing_policy_configured_test.py | 320 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 108 +++++- 8 files changed, 625 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py create mode 100644 tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index af54d34cc5..3fb73bdca9 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331). - Add service Defender to Microsoft365 with one check for Common Attachments filter enabled in Malware Policies [(#7425)](https://github.com/prowler-cloud/prowler/pull/7425). +- Add check for Antiphishing Policy well configured in service Defender in M365 [(#7453)](https://github.com/prowler-cloud/prowler/pull/7453). - Add check for Notifications for Internal users enabled in Malware Policies from service Defender in M365 [(#7435)](https://github.com/prowler-cloud/prowler/pull/7435). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 838d85311d..06bb40b5b8 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -188,6 +188,49 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json") + def get_antiphishing_policy(self) -> dict: + """ + Get Defender Antiphishing Policy. + + Retrieves the current Defender anti-phishing policy settings. + + Returns: + dict: Antiphishing policy settings in JSON format. + + Example: + >>> get_antiphishing_policy() + { + "EnableSpoofIntelligence": true, + "AuthenticationFailAction": "Quarantine", + "DmarcRejectAction": "Quarantine", + "DmarcQuarantineAction": "Quarantine", + "EnableFirstContactSafetyTips": true, + "EnableUnauthenticatedSender": true, + "EnableViaTag": true, + "HonorDmarcPolicy": true, + "IsDefault": false + } + """ + return self.execute("Get-AntiPhishPolicy | ConvertTo-Json") + + def get_antiphishing_rules(self) -> dict: + """ + Get Defender Antiphishing Rules. + + Retrieves the current Defender anti-phishing rules. + + Returns: + dict: Antiphishing rules in JSON format. + + Example: + >>> get_antiphishing_rules() + { + "Name": "Rule1", + "State": Enabled, + } + """ + return self.execute("Get-AntiPhishRule | ConvertTo-Json") + def get_organization_config(self) -> dict: """ Get Exchange Online Organization Configuration. diff --git a/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/__init__.py b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.metadata.json b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.metadata.json new file mode 100644 index 0000000000..1929eae755 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_antiphishing_policy_configured", + "CheckTitle": "Ensure anti-phishing policies are properly configured and active.", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "low", + "ResourceType": "Defender Anti-Phishing Policy", + "Description": "Ensure that anti-phishing policies are created and configured for specific users, groups, or domains, taking precedence over the default policy. This check verifies the existence of rules within policies and validates specific policy settings such as spoof intelligence, DMARC actions, safety tips, and unauthenticated sender actions.", + "Risk": "Without anti-phishing policies, organizations may rely solely on default settings, which might not adequately protect against phishing attacks targeted at specific users, groups, or domains. This increases the risk of successful phishing attempts and potential data breaches.", + "RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/set-up-anti-phishing-policies?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "$params = @{Name='';PhishThresholdLevel=3;EnableTargetedUserProtection=$true;EnableOrganizationDomainsProtection=$true;EnableMailboxIntelligence=$true;EnableMailboxIntelligenceProtection=$true;EnableSpoofIntelligence=$true;TargetedUserProtectionAction='Quarantine';TargetedDomainProtectionAction='Quarantine';MailboxIntelligenceProtectionAction='Quarantine';TargetedUserQuarantineTag='DefaultFullAccessWithNotificationPolicy';MailboxIntelligenceQuarantineTag='DefaultFullAccessWithNotificationPolicy';TargetedDomainQuarantineTag='DefaultFullAccessWithNotificationPolicy';EnableFirstContactSafetyTips=$true;EnableSimilarUsersSafetyTips=$true;EnableSimilarDomainsSafetyTips=$true;EnableUnusualCharactersSafetyTips=$true;HonorDmarcPolicy=$true}; New-AntiPhishPolicy @params; New-AntiPhishRule -Name $params.Name -AntiPhishPolicy $params.Name -RecipientDomainIs (Get-AcceptedDomain).Name -Priority 0", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules. 3. On the Policies & rules page select Threat policies. 4. Under Policies, select Anti-phishing 5. Ensure policies have rules with the state set to 'on' and validate settings: spoof intelligence enabled, spoof intelligence action set to 'Quarantine', DMARC reject and quarantine actions, safety tips enabled, unauthenticated sender action enabled, show tag enabled, and honor DMARC policy enabled. If not, modify them to be as recommended.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and configure anti-phishing policies for specific users, groups, or domains to enhance protection against phishing attacks.", + "Url": "https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/set-up-anti-phishing-policies?view=o365-worldwide" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py new file mode 100644 index 0000000000..18ac8f9949 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py @@ -0,0 +1,59 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_antiphishing_policy_configured(Check): + """ + Check if an anti-phishing policy is established and properly configured in the Defender service. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if an anti-phishing policy is established and properly configured. + + This method checks the Defender anti-phishing policies to ensure they are configured + according to best practices. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + for policy_name, policy in defender_client.antiphishing_policies.items(): + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Anti-Phishing Policy", + resource_id=policy_name, + ) + report.status = "FAIL" + report.status_extended = ( + f"Anti-phishing policy {policy_name} is not properly configured." + ) + + if ( + not policy.default + and policy_name in defender_client.antiphising_rules + and defender_client.antiphising_rules[policy_name].state.lower() + == "enabled" + ) or policy.default: + if ( + policy.spoof_intelligence + and policy.spoof_intelligence_action.lower() == "quarantine" + and policy.dmarc_reject_action.lower() == "quarantine" + and policy.dmarc_quarantine_action.lower() == "quarantine" + and policy.safety_tips + and policy.unauthenticated_sender_action + and policy.show_tag + and policy.honor_dmarc_policy + ): + report.status = "PASS" + report.status_extended = f"Anti-phishing policy {policy_name} is properly configured and enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 3ad098d0b5..37948bfd6e 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -10,6 +10,8 @@ class Defender(M365Service): super().__init__(provider) self.powershell.connect_exchange_online() self.malware_policies = self._get_malware_filter_policy() + self.antiphishing_policies = self._get_antiphising_policy() + self.antiphising_rules = self._get_antiphising_rules() self.powershell.close() def _get_malware_filter_policy(self): @@ -39,9 +41,73 @@ class Defender(M365Service): ) return malware_policies + def _get_antiphising_policy(self): + logger.info("Microsoft365 - Getting Defender antiphishing policy...") + antiphishing_policies = {} + try: + antiphishing_policy = self.powershell.get_antiphishing_policy() + if isinstance(antiphishing_policy, dict): + antiphishing_policy = [antiphishing_policy] + for policy in antiphishing_policy: + if policy: + antiphishing_policies[policy.get("Name", "")] = AntiphishingPolicy( + spoof_intelligence=policy.get("EnableSpoofIntelligence", True), + spoof_intelligence_action=policy.get( + "AuthenticationFailAction", "" + ), + dmarc_reject_action=policy.get("DmarcRejectAction", ""), + dmarc_quarantine_action=policy.get("DmarcQuarantineAction", ""), + safety_tips=policy.get("EnableFirstContactSafetyTips", True), + unauthenticated_sender_action=policy.get( + "EnableUnauthenticatedSender", True + ), + show_tag=policy.get("EnableViaTag", True), + honor_dmarc_policy=policy.get("HonorDmarcPolicy", True), + default=policy.get("IsDefault", False), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return antiphishing_policies + + def _get_antiphising_rules(self): + logger.info("Microsoft365 - Getting Defender antiphishing rules...") + antiphishing_rules = {} + try: + antiphishing_rule = self.powershell.get_antiphishing_rules() + if isinstance(antiphishing_rule, dict): + antiphishing_rule = [antiphishing_rule] + for rule in antiphishing_rule: + if rule: + antiphishing_rules[rule.get("Name", "")] = AntiphishingRule( + state=rule.get("State", ""), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return antiphishing_rules + class DefenderMalwarePolicy(BaseModel): enable_file_filter: bool identity: str enable_internal_sender_admin_notifications: bool internal_sender_admin_address: str + + +class AntiphishingPolicy(BaseModel): + spoof_intelligence: bool + spoof_intelligence_action: str + dmarc_reject_action: str + dmarc_quarantine_action: str + safety_tips: bool + unauthenticated_sender_action: bool + show_tag: bool + honor_dmarc_policy: bool + default: bool + + +class AntiphishingRule(BaseModel): + state: str diff --git a/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py b/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py new file mode 100644 index 0000000000..b460646dae --- /dev/null +++ b/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py @@ -0,0 +1,320 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_antiphishing_policy_configured: + def test_properly_configured_custom_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + AntiphishingRule, + ) + + defender_client.antiphishing_policies = { + "Policy1": AntiphishingPolicy( + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=False, + ) + } + defender_client.antiphising_rules = { + "Policy1": AntiphishingRule(state="Enabled") + } + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Anti-phishing policy Policy1 is properly configured and enabled." + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["Policy1"].dict() + ) + assert result[0].resource_name == "Defender Anti-Phishing Policy" + assert result[0].resource_id == "Policy1" + assert result[0].location == "global" + + def test_not_properly_configured_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + AntiphishingRule, + ) + + defender_client.antiphishing_policies = { + "Policy2": AntiphishingPolicy( + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=False, + ) + } + defender_client.antiphising_rules = { + "Policy2": AntiphishingRule(state="Enabled") + } + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Anti-phishing policy Policy2 is not properly configured." + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["Policy2"].dict() + ) + assert result[0].resource_name == "Defender Anti-Phishing Policy" + assert result[0].resource_id == "Policy2" + assert result[0].location == "global" + + def test_properly_configured_default_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + ) + + defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=True, + ) + } + defender_client.antiphising_rules = {} + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Anti-phishing policy Default is properly configured and enabled." + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + assert result[0].resource_name == "Defender Anti-Phishing Policy" + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_default_policy_not_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + ) + + defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=True, + ) + } + defender_client.antiphising_rules = {} + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Anti-phishing policy Default is not properly configured." + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + assert result[0].resource_name == "Defender Anti-Phishing Policy" + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_no_antiphishing_policies(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + + defender_client.antiphishing_policies = {} + defender_client.antiphising_rules = {} + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert result == [] + + def test_custom_policy_without_rule(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + ) + + defender_client.antiphishing_policies = { + "PolicyX": AntiphishingPolicy( + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=False, + ) + } + defender_client.antiphising_rules = {} + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Anti-phishing policy PolicyX is not properly configured." + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["PolicyX"].dict() + ) + assert result[0].resource_name == "Defender Anti-Phishing Policy" + assert result[0].resource_id == "PolicyX" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 1ef9ff1607..3e61bb0673 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -3,6 +3,8 @@ from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + AntiphishingRule, Defender, DefenderMalwarePolicy, ) @@ -26,6 +28,44 @@ def mock_defender_get_malware_filter_policy(_): ] +def mock_defender_get_antiphising_policy(_): + return { + "Policy1": AntiphishingPolicy( + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Reject", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=False, + ), + "Policy2": AntiphishingPolicy( + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=True, + ), + } + + +def mock_defender_get_antiphising_rules(_): + return { + "Policy1": AntiphishingRule( + state="Enabled", + ), + "Policy2": AntiphishingRule( + state="Disabled", + ), + } + + class Test_Defender_Service: def test_get_client(self): with ( @@ -58,8 +98,6 @@ class Test_Defender_Service: ) ) malware_policies = defender_client.malware_policies - assert malware_policies[0].enable_file_filter is False - assert malware_policies[0].identity == "Policy1" assert ( malware_policies[0].enable_internal_sender_admin_notifications is False ) @@ -73,3 +111,69 @@ class Test_Defender_Service: malware_policies[1].internal_sender_admin_address == "security@example.com" ) + defender_client.powershell.close() + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_policy", + new=mock_defender_get_antiphising_policy, + ) + def test_get_antiphising_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + antiphishing_policies = defender_client.antiphishing_policies + assert antiphishing_policies["Policy1"].spoof_intelligence is True + assert ( + antiphishing_policies["Policy1"].spoof_intelligence_action + == "Quarantine" + ) + assert antiphishing_policies["Policy1"].dmarc_reject_action == "Reject" + assert ( + antiphishing_policies["Policy1"].dmarc_quarantine_action == "Quarantine" + ) + assert antiphishing_policies["Policy1"].safety_tips is True + assert ( + antiphishing_policies["Policy1"].unauthenticated_sender_action is True + ) + assert antiphishing_policies["Policy1"].show_tag is True + assert antiphishing_policies["Policy1"].honor_dmarc_policy is True + assert antiphishing_policies["Policy1"].default is False + assert antiphishing_policies["Policy2"].spoof_intelligence is False + assert antiphishing_policies["Policy2"].spoof_intelligence_action == "None" + assert antiphishing_policies["Policy2"].dmarc_reject_action == "None" + assert antiphishing_policies["Policy2"].dmarc_quarantine_action == "None" + assert antiphishing_policies["Policy2"].safety_tips is False + assert ( + antiphishing_policies["Policy2"].unauthenticated_sender_action is False + ) + assert antiphishing_policies["Policy2"].show_tag is False + assert antiphishing_policies["Policy2"].honor_dmarc_policy is False + assert antiphishing_policies["Policy2"].default is True + defender_client.powershell.close() + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_rules", + new=mock_defender_get_antiphising_rules, + ) + def test_get_antiphising_rules(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + antiphishing_rules = defender_client.antiphising_rules + assert antiphishing_rules["Policy1"].state == "Enabled" + assert antiphishing_rules["Policy2"].state == "Disabled" + defender_client.powershell.close() From 0b6aa0ddcd54abb577faea148117991cb71ed7e6 Mon Sep 17 00:00:00 2001 From: Felix Dreissig Date: Fri, 18 Apr 2025 22:25:44 +0200 Subject: [PATCH 178/359] fix(aws): remove `SHA-1` from ACM insecure key algorithms (#7547) --- contrib/k8s/helm/prowler-api/values.yaml | 1 - prowler/config/config.yaml | 1 - .../acm_certificates_with_secure_key_algorithms.py | 2 +- tests/config/config_test.py | 1 - tests/config/fixtures/config.yaml | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/contrib/k8s/helm/prowler-api/values.yaml b/contrib/k8s/helm/prowler-api/values.yaml index 16cd48058c..40a7fda298 100644 --- a/contrib/k8s/helm/prowler-api/values.yaml +++ b/contrib/k8s/helm/prowler-api/values.yaml @@ -399,7 +399,6 @@ mainConfig: [ "RSA-1024", "P-192", - "SHA-1", ] # AWS EKS Configuration diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index c8a2ee7e50..26b196e178 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -327,7 +327,6 @@ aws: [ "RSA-1024", "P-192", - "SHA-1", ] # AWS EKS Configuration diff --git a/prowler/providers/aws/services/acm/acm_certificates_with_secure_key_algorithms/acm_certificates_with_secure_key_algorithms.py b/prowler/providers/aws/services/acm/acm_certificates_with_secure_key_algorithms/acm_certificates_with_secure_key_algorithms.py index f2135cf77a..2ac5dd9199 100644 --- a/prowler/providers/aws/services/acm/acm_certificates_with_secure_key_algorithms/acm_certificates_with_secure_key_algorithms.py +++ b/prowler/providers/aws/services/acm/acm_certificates_with_secure_key_algorithms/acm_certificates_with_secure_key_algorithms.py @@ -14,7 +14,7 @@ class acm_certificates_with_secure_key_algorithms(Check): report.status = "PASS" report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} uses a secure key algorithm ({certificate.key_algorithm})." if certificate.key_algorithm in acm_client.audit_config.get( - "insecure_key_algorithms", ["RSA-1024", "P-192", "SHA-1"] + "insecure_key_algorithms", ["RSA-1024", "P-192"] ): report.status = "FAIL" report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} does not use a secure key algorithm ({certificate.key_algorithm})." diff --git a/tests/config/config_test.py b/tests/config/config_test.py index d796bfde1a..465d16a05a 100644 --- a/tests/config/config_test.py +++ b/tests/config/config_test.py @@ -297,7 +297,6 @@ config_aws = { "insecure_key_algorithms": [ "RSA-1024", "P-192", - "SHA-1", ], "eks_required_log_types": [ "api", diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml index e9a4e6fad2..4d528e97da 100644 --- a/tests/config/fixtures/config.yaml +++ b/tests/config/fixtures/config.yaml @@ -317,7 +317,6 @@ aws: [ "RSA-1024", "P-192", - "SHA-1", ] # AWS EKS Configuration From bd56e039919b449016f44ac4a32ff2b6304c1437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:09:22 +0200 Subject: [PATCH 179/359] chore(gha): trigger cloud pull-request when a PR is merged (#7212) --- .github/workflows/pull-request-merged.yml | 33 +++++++++++++++++++++++ .github/workflows/sdk-codeql.yml | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 .github/workflows/pull-request-merged.yml diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml new file mode 100644 index 0000000000..e27c76fb83 --- /dev/null +++ b/.github/workflows/pull-request-merged.yml @@ -0,0 +1,33 @@ +name: Prowler - Merged Pull Request + +on: + pull_request_target: + branches: ['master'] + types: ['closed'] + +jobs: + trigger-cloud-pull-request: + name: Trigger Cloud Pull Request + if: github.event.pull_request.merged == true && github.repository == "prowler-cloud/prowler" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set short git commit SHA + id: vars + run: | + shortSha=$(git rev-parse --short ${{ github.sha }}) + echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV + + - name: Trigger pull request + uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 + with: + token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} + repository: ${{ secrets.CLOUD_DISPATCH }} + event-type: prowler-pull-request-merged + client-payload: '{ + "PROWLER_COMMIT_SHA": "${{ github.sha }}", + "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", + "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", + "PROWLER_PR_BODY": "${{ github.event.pull_request.body }}" + }' diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index cb21358991..ac48ea1163 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -21,6 +21,7 @@ on: paths-ignore: - 'ui/**' - 'api/**' + - '.github/**' pull_request: branches: - "master" @@ -30,6 +31,7 @@ on: paths-ignore: - 'ui/**' - 'api/**' + - '.github/**' schedule: - cron: '00 12 * * *' From 4d217e642b6644942f97d0fd71b09c803ad28e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:11:17 +0200 Subject: [PATCH 180/359] chore: fix trigger (#7551) --- .github/workflows/pull-request-merged.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index e27c76fb83..7d32dcbb2e 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -8,7 +8,7 @@ on: jobs: trigger-cloud-pull-request: name: Trigger Cloud Pull Request - if: github.event.pull_request.merged == true && github.repository == "prowler-cloud/prowler" + if: github.event.pull_request.merged == true && github.repository == 'prowler-cloud/prowler' runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 From 29d3bb9f9abb8f1206bb00793d5711d8abe6fb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:16:03 +0200 Subject: [PATCH 181/359] chore: fix json body (#7552) --- .github/workflows/pull-request-merged.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index 7d32dcbb2e..fdd77c8475 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -29,5 +29,5 @@ jobs: "PROWLER_COMMIT_SHA": "${{ github.sha }}", "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", - "PROWLER_PR_BODY": "${{ github.event.pull_request.body }}" + "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} }' From 08f6d4b69b188a7c3a5e38daa1627d58ad9bd9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:57:50 +0200 Subject: [PATCH 182/359] chore: pass labels (#7553) --- .github/workflows/pull-request-merged.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index fdd77c8475..366f646c5e 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -30,4 +30,5 @@ jobs: "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} + "PROWLER_PR_LABELS": ${{ github.event.pull_request.labels }}, }' From 734fa5a4e678707d205863cc827e1c65905bc6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 12:03:14 +0200 Subject: [PATCH 183/359] chore: fix merged PR action, incorrect order on payload (#7554) --- .github/workflows/pull-request-merged.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index 366f646c5e..9d493099cb 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -29,6 +29,6 @@ jobs: "PROWLER_COMMIT_SHA": "${{ github.sha }}", "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", - "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} "PROWLER_PR_LABELS": ${{ github.event.pull_request.labels }}, + "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} }' From b5ea418933c77f4ff2cd2f9207fb3e66f1d8a41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 12:10:18 +0200 Subject: [PATCH 184/359] chore: pass labels as json is required (#7555) --- .github/workflows/pull-request-merged.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index 9d493099cb..8d6eda8843 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -29,6 +29,6 @@ jobs: "PROWLER_COMMIT_SHA": "${{ github.sha }}", "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", - "PROWLER_PR_LABELS": ${{ github.event.pull_request.labels }}, + "PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels) }}, "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} }' From f1df8ba458cbaf93a3d97bd875efe8abc6c4fb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 12:46:42 +0200 Subject: [PATCH 185/359] chore: revert pass labels (#7556) --- .github/workflows/pull-request-merged.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index 8d6eda8843..fdd77c8475 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -29,6 +29,5 @@ jobs: "PROWLER_COMMIT_SHA": "${{ github.sha }}", "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", - "PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels) }}, "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} }' From 348d1a2fdacb5f7512d58d47c050b89165e7324a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:43:40 +0200 Subject: [PATCH 186/359] chore: pass labels on PR merge trigger (#7558) --- .github/workflows/pull-request-merged.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index fdd77c8475..500ca5d0c4 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -29,5 +29,6 @@ jobs: "PROWLER_COMMIT_SHA": "${{ github.sha }}", "PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}", "PROWLER_PR_TITLE": "${{ github.event.pull_request.title }}", + "PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels.*.name) }}, "PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }} }' From 00f1c0253266bdf9eaf1177a33175b9df5e8b884 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 22 Apr 2025 16:46:15 +0545 Subject: [PATCH 187/359] chore(tests): Split by provider in the SDK (#7564) --- .github/workflows/sdk-pull-request.yml | 96 +++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index bd81c2c5c3..650e80af63 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -107,11 +107,102 @@ jobs: run: | /tmp/hadolint Dockerfile --ignore=DL3013 - - name: Test with pytest + # Test AWS + - name: AWS - Check if any file has changed + id: aws-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/aws + ./tests/providers/aws + + - name: AWS - Test + if: steps.aws-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/aws --cov-report=xml:aws_coverage.xml tests/providers/aws + + # Test Azure + - name: Azure - Check if any file has changed + id: azure-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/azure + ./tests/providers/azure + + - name: Azure - Test + if: steps.azure-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/azure --cov-report=xml:azure_coverage.xml tests/providers/azure + + # Test GCP + - name: GCP - Check if any file has changed + id: gcp-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/gcp + ./tests/providers/gcp + + - name: GCP - Test + if: steps.gcp-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/gcp --cov-report=xml:gcp_coverage.xml tests/providers/gcp + + # Test Kubernetes + - name: Kubernetes - Check if any file has changed + id: kubernetes-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/kubernetes + ./tests/providers/kubernetes + + - name: Kubernetes - Test + if: steps.kubernetes-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/kubernetes --cov-report=xml:kubernetes_coverage.xml tests/providers/kubernetes + + # Test NHN + - name: NHN - Check if any file has changed + id: nhn-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/nhn + ./tests/providers/nhn + + - name: NHN - Test + if: steps.nhn-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/nhn --cov-report=xml:nhn_coverage.xml tests/providers/nhn + + # Test M365 + - name: M365 - Check if any file has changed + id: m365-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/m365 + ./tests/providers/m365 + + - name: M365 - Test + if: steps.m365-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/m365 --cov-report=xml:m365_coverage.xml tests/providers/m365 + + # Common Tests + - name: Lib - Test if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' run: | - poetry run pytest -n auto --cov=./prowler --cov-report=xml tests + poetry run pytest -n auto --cov=./prowler/lib --cov-report=xml:lib_coverage.xml tests/lib + - name: Config - Test + if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/config --cov-report=xml:config_coverage.xml tests/config + + # Codecov - name: Upload coverage reports to Codecov if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 @@ -119,3 +210,4 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: flags: prowler + files: ./aws_coverage.xml,./azure_coverage.xml,./gcp_coverage.xml,./kubernetes_coverage.xml,./nhn_coverage.xml,./m365_coverage.xml,./lib_coverage.xml,./config_coverage.xml From e897978c3e09c963e47cb5082e33f498856c3528 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 22 Apr 2025 08:21:17 -0500 Subject: [PATCH 188/359] fix(azure): handle new FlowLog properties (#7546) --- prowler/CHANGELOG.md | 1 + .../azure/services/network/network_service.py | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 3fb73bdca9..22feb8bb6a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -22,6 +22,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Fix package name location in pyproject.toml while replicating for prowler-cloud [(#7531)](https://github.com/prowler-cloud/prowler/pull/7531). - Remove cache in PyPI release action [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532). - Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). +- Handle new FlowLog model properties in Azure [(#7546)](https://github.com/prowler-cloud/prowler/pull/7546). --- diff --git a/prowler/providers/azure/services/network/network_service.py b/prowler/providers/azure/services/network/network_service.py index fb0e6f90ba..75c4f3a971 100644 --- a/prowler/providers/azure/services/network/network_service.py +++ b/prowler/providers/azure/services/network/network_service.py @@ -78,15 +78,18 @@ class Network(AzureService): FlowLog( id=flow_log.id, name=flow_log.name, - enabled=getattr( - getattr(flow_log, "properties", None), - "enabled", - False, - ), - retention_policy=getattr( - getattr(flow_log, "properties", None), - "retentionPolicy", - None, + enabled=flow_log.enabled, + retention_policy=RetentionPolicy( + enabled=( + flow_log.retention_policy.enabled + if flow_log.retention_policy + else False + ), + days=( + flow_log.retention_policy.days + if flow_log.retention_policy + else 0 + ), ), ) for flow_log in flow_logs From bb527024d9b33c68cb44d29bb69519295b7fca9c Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Tue, 22 Apr 2025 15:32:22 +0200 Subject: [PATCH 189/359] chore(regions_update): Changes in regions for AWS services (#7550) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- .../providers/aws/aws_regions_by_service.json | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 633973067d..210a12a965 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -4186,12 +4186,10 @@ "entityresolution": { "regions": { "aws": [ - "af-south-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", - "ca-central-1", "eu-central-1", "eu-west-1", "eu-west-2", @@ -7841,17 +7839,6 @@ "aws-us-gov": [] } }, - "opsworkscm": { - "regions": { - "aws": [ - "ap-southeast-2", - "eu-west-1", - "us-east-1" - ], - "aws-cn": [], - "aws-us-gov": [] - } - }, "opsworkspuppetenterprise": { "regions": { "aws": [ @@ -8051,6 +8038,44 @@ "aws-us-gov": [] } }, + "pca-connector-scep": { + "regions": { + "aws": [ + "af-south-1", + "ap-east-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-south-2", + "ap-southeast-1", + "ap-southeast-2", + "ap-southeast-3", + "ap-southeast-4", + "ap-southeast-5", + "ca-central-1", + "ca-west-1", + "eu-central-1", + "eu-central-2", + "eu-north-1", + "eu-south-1", + "eu-south-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "il-central-1", + "me-central-1", + "me-south-1", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2" + ], + "aws-cn": [], + "aws-us-gov": [] + } + }, "pcs": { "regions": { "aws": [ @@ -10434,11 +10459,19 @@ "socialmessaging": { "regions": { "aws": [ + "af-south-1", + "ap-northeast-1", + "ap-northeast-2", "ap-south-1", + "ap-south-2", "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", + "eu-south-2", "eu-west-1", "eu-west-2", + "sa-east-1", "us-east-1", "us-east-2", "us-west-2" From 2ebf217bb0122f66eeedf40079d12578f47b4c72 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 22 Apr 2025 19:18:40 +0545 Subject: [PATCH 190/359] fix(k8s): Remove command as it is not needed (#7570) --- contrib/k8s/helm/prowler-cli/templates/job.yaml | 1 - kubernetes/job.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/contrib/k8s/helm/prowler-cli/templates/job.yaml b/contrib/k8s/helm/prowler-cli/templates/job.yaml index 1cb0c078ea..408c28dfac 100644 --- a/contrib/k8s/helm/prowler-cli/templates/job.yaml +++ b/contrib/k8s/helm/prowler-cli/templates/job.yaml @@ -16,7 +16,6 @@ spec: containers: - name: prowler image: {{ .Values.image.repository }}:{{ .Values.image.tag }} - command: ["prowler"] args: ["kubernetes", "-z", "-b"] imagePullPolicy: {{ .Values.image.pullPolicy }} volumeMounts: diff --git a/kubernetes/job.yaml b/kubernetes/job.yaml index ac21722eb0..5eb791827b 100644 --- a/kubernetes/job.yaml +++ b/kubernetes/job.yaml @@ -13,7 +13,6 @@ spec: containers: - name: prowler image: toniblyx/prowler:stable - command: ["prowler"] args: ["kubernetes", "-z"] imagePullPolicy: Always volumeMounts: From b07080245dd38c2e21c7122594456fe2823a9dd3 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 22 Apr 2025 15:58:07 +0200 Subject: [PATCH 191/359] feat(defender): add new check `defender_antispam_outbound_policy_configured` (#7480) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 37 +++ .../__init__.py | 0 ...m_outbound_policy_configured.metadata.json | 30 +++ ...der_antispam_outbound_policy_configured.py | 54 ++++ .../services/defender/defender_service.py | 66 ++++- ...ntispam_outbound_policy_configured_test.py | 248 ++++++++++++++++++ ..._common_attachments_filter_enabled_test.py | 8 +- ...ons_internal_users_malware_enabled_test.py | 12 +- .../defender/m365_defender_service_test.py | 92 ++++++- 10 files changed, 533 insertions(+), 15 deletions(-) create mode 100644 prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py create mode 100644 tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 22feb8bb6a..d42960d4d7 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331). - Add service Defender to Microsoft365 with one check for Common Attachments filter enabled in Malware Policies [(#7425)](https://github.com/prowler-cloud/prowler/pull/7425). +- Add check for Outbound Antispam Policy well configured in service Defender for M365 [(#7480)](https://github.com/prowler-cloud/prowler/pull/7480). - Add check for Antiphishing Policy well configured in service Defender in M365 [(#7453)](https://github.com/prowler-cloud/prowler/pull/7453). - Add check for Notifications for Internal users enabled in Malware Policies from service Defender in M365 [(#7435)](https://github.com/prowler-cloud/prowler/pull/7435). - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 06bb40b5b8..573cdd5adf 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -188,6 +188,43 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json") + def get_outbound_spam_filter_policy(self) -> dict: + """ + Get Defender Outbound Spam Filter Policy. + + Retrieves the current Defender outbound spam filter policy settings. + + Returns: + dict: Outbound spam filter policy settings in JSON format. + + Example: + >>> get_outbound_spam_filter_policy() + { + "NotifyOutboundSpam": true, + "BccSuspiciousOutboundMail": true, + "BccSuspiciousOutboundAdditionalRecipients": [], + "NotifyOutboundSpamRecipients": [] + } + """ + return self.execute("Get-HostedOutboundSpamFilterPolicy | ConvertTo-Json") + + def get_outbound_spam_filter_rule(self) -> dict: + """ + Get Defender Outbound Spam Filter Rule. + + Retrieves the current Defender outbound spam filter rule settings. + + Returns: + dict: Outbound spam filter rule settings in JSON format. + + Example: + >>> get_outbound_spam_filter_rule() + { + "State": "Enabled" + } + """ + return self.execute("Get-HostedOutboundSpamFilterRule | ConvertTo-Json") + def get_antiphishing_policy(self) -> dict: """ Get Defender Antiphishing Policy. diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/__init__.py b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.metadata.json b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.metadata.json new file mode 100644 index 0000000000..0d7b2ecc76 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_antispam_outbound_policy_configured", + "CheckTitle": "Ensure Defender Outbound Spam Policies are set to notify administrators.", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "low", + "ResourceType": "Defender Anti-Spam Policy", + "Description": "Ensure that outbound anti-spam policies are configured to notify administrators and copy suspicious outbound messages to designated recipients when a sender is blocked for sending spam emails.", + "Risk": "Without outbound spam notifications and message copies, compromised accounts may go undetected, increasing the risk of reputation damage or data leakage through unauthorized email activity.", + "RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-protection-about", + "Remediation": { + "Code": { + "CLI": "$BccEmailAddress = @(\"\")\n$NotifyEmailAddress = @(\"\")\nSet-HostedOutboundSpamFilterPolicy -Identity Default -BccSuspiciousOutboundAdditionalRecipients $BccEmailAddress -BccSuspiciousOutboundMail $true -NotifyOutboundSpam $true -NotifyOutboundSpamRecipients $NotifyEmailAddress", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules > Threat policies. 3. Under Policies, select Anti-spam. 4. Click on the Anti-spam outbound policy (default). 5. Select Edit protection settings then under Notifications: 6. Check 'Send a copy of suspicious outbound messages or message that exceed these limits to these users and groups' and enter the email addresses. 7. Check 'Notify these users and groups if a sender is blocked due to sending outbound spam' and enter the desired email addresses. 8. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Configure Defender outbound spam filter policies to notify administrators and copy suspicious outbound messages when users are blocked for sending spam.", + "Url": "https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-protection-about" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Ensure settings are applied to the highest priority policy if custom policies exist. Default values do not notify or copy outbound spam messages by default." +} diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py new file mode 100644 index 0000000000..b4a0f2e31b --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py @@ -0,0 +1,54 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_antispam_outbound_policy_configured(Check): + """ + Check if the Exchange Online Spam Policies are configured to notify administrators + when a sender is blocked for sending spam emails. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if the Exchange Online Spam Policies notify administrators + when a sender is blocked for sending spam emails. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + for policy_name, policy in defender_client.outbound_spam_policies.items(): + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Outbound Spam Policy", + resource_id=policy_name, + ) + report.status = "FAIL" + report.status_extended = ( + f"Outbound Spam Policy {policy_name} is not properly configured." + ) + + if ( + not policy.default + and policy_name in defender_client.outbound_spam_rules + and defender_client.outbound_spam_rules[policy_name].state.lower() + == "enabled" + ) or policy.default: + if ( + policy.notify_limit_exceeded + and policy.notify_sender_blocked + and policy.notify_limit_exceeded_addresses + and policy.notify_sender_blocked_addresses + ): + report.status = "PASS" + report.status_extended = f"Outbound Spam Policy {policy_name} is properly configured and enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 37948bfd6e..05e57d669d 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -1,3 +1,5 @@ +from typing import List + from pydantic import BaseModel from prowler.lib.logger import logger @@ -10,6 +12,8 @@ class Defender(M365Service): super().__init__(provider) self.powershell.connect_exchange_online() self.malware_policies = self._get_malware_filter_policy() + self.outbound_spam_policies = self._get_outbound_spam_filter_policy() + self.outbound_spam_rules = self._get_outbound_spam_filter_rule() self.antiphishing_policies = self._get_antiphising_policy() self.antiphising_rules = self._get_antiphising_rules() self.powershell.close() @@ -24,7 +28,7 @@ class Defender(M365Service): for policy in malware_policy: if policy: malware_policies.append( - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=policy.get("EnableFileFilter", True), identity=policy.get("Identity", ""), enable_internal_sender_admin_notifications=policy.get( @@ -89,8 +93,54 @@ class Defender(M365Service): ) return antiphishing_rules + def _get_outbound_spam_filter_policy(self): + logger.info("Microsoft365 - Getting Defender outbound spam filter policy...") + outbound_spam_policies = {} + try: + outbound_spam_policy = self.powershell.get_outbound_spam_filter_policy() + if isinstance(outbound_spam_policy, dict): + outbound_spam_policy = [outbound_spam_policy] + for policy in outbound_spam_policy: + if policy: + outbound_spam_policies[policy.get("Name", "")] = OutboundSpamPolicy( + notify_sender_blocked=policy.get("NotifyOutboundSpam", True), + notify_limit_exceeded=policy.get( + "BccSuspiciousOutboundMail", True + ), + notify_limit_exceeded_addresses=policy.get( + "BccSuspiciousOutboundAdditionalRecipients", [] + ), + notify_sender_blocked_addresses=policy.get( + "NotifyOutboundSpamRecipients", [] + ), + default=policy.get("IsDefault", False), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return outbound_spam_policies -class DefenderMalwarePolicy(BaseModel): + def _get_outbound_spam_filter_rule(self): + logger.info("Microsoft365 - Getting Defender outbound spam filter rule...") + outbound_spam_rules = {} + try: + outbound_spam_rule = self.powershell.get_outbound_spam_filter_rule() + if isinstance(outbound_spam_rule, dict): + outbound_spam_rule = [outbound_spam_rule] + for rule in outbound_spam_rule: + if rule: + outbound_spam_rules[rule.get("Name", "")] = OutboundSpamRule( + state=rule.get("State", "Disabled"), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return outbound_spam_rules + + +class MalwarePolicy(BaseModel): enable_file_filter: bool identity: str enable_internal_sender_admin_notifications: bool @@ -111,3 +161,15 @@ class AntiphishingPolicy(BaseModel): class AntiphishingRule(BaseModel): state: str + + +class OutboundSpamPolicy(BaseModel): + notify_sender_blocked: bool + notify_limit_exceeded: bool + notify_limit_exceeded_addresses: List[str] + notify_sender_blocked_addresses: List[str] + default: bool + + +class OutboundSpamRule(BaseModel): + state: str diff --git a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py new file mode 100644 index 0000000000..fe7c338838 --- /dev/null +++ b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py @@ -0,0 +1,248 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_antispam_outbound_policy_configured: + def test_properly_configured_custom_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Policy1": OutboundSpamPolicy( + notify_sender_blocked=True, + notify_limit_exceeded=True, + notify_limit_exceeded_addresses=["test@correo.com"], + notify_sender_blocked_addresses=["test@correo.com"], + default=False, + ) + } + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule(state="Enabled") + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Outbound Spam Policy Policy1 is properly configured and enabled." + ) + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + assert result[0].resource_name == "Defender Outbound Spam Policy" + assert result[0].resource_id == "Policy1" + assert result[0].location == "global" + + def test_not_properly_configured_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Policy2": OutboundSpamPolicy( + notify_sender_blocked=False, + notify_limit_exceeded=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=False, + ) + } + defender_client.outbound_spam_rules = { + "Policy2": OutboundSpamRule(state="Enabled") + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Outbound Spam Policy Policy2 is not properly configured." + ) + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Policy2"].dict() + ) + assert result[0].resource_name == "Defender Outbound Spam Policy" + assert result[0].resource_id == "Policy2" + assert result[0].location == "global" + + def test_properly_configured_default_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + notify_sender_blocked=True, + notify_limit_exceeded=True, + notify_limit_exceeded_addresses=["test@correo.com"], + notify_sender_blocked_addresses=["test@correo.com"], + default=True, + ) + } + defender_client.outbound_spam_rules = {} + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Outbound Spam Policy Default is properly configured and enabled." + ) + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + assert result[0].resource_name == "Defender Outbound Spam Policy" + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_policy_without_rule(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + ) + + defender_client.outbound_spam_policies = { + "PolicyX": OutboundSpamPolicy( + notify_sender_blocked=True, + notify_limit_exceeded=True, + notify_limit_exceeded_addresses=["admin@org.com"], + notify_sender_blocked_addresses=["admin@org.com"], + default=False, + ) + } + defender_client.outbound_spam_rules = {} + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Outbound Spam Policy PolicyX is not properly configured." + ) + assert ( + result[0].resource + == defender_client.outbound_spam_policies["PolicyX"].dict() + ) + assert result[0].resource_name == "Defender Outbound Spam Policy" + assert result[0].resource_id == "PolicyX" + assert result[0].location == "global" + + def test_no_outbound_spam_policies(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + + defender_client.outbound_spam_policies = {} + defender_client.outbound_spam_rules = {} + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py index 1e06abb97b..f416559e35 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py @@ -26,11 +26,11 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: defender_malware_policy_common_attachments_filter_enabled, ) from prowler.providers.m365.services.defender.defender_service import ( - DefenderMalwarePolicy, + MalwarePolicy, ) defender_client.malware_policies = [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=False, identity="Policy1", enable_internal_sender_admin_notifications=False, @@ -74,11 +74,11 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: defender_malware_policy_common_attachments_filter_enabled, ) from prowler.providers.m365.services.defender.defender_service import ( - DefenderMalwarePolicy, + MalwarePolicy, ) defender_client.malware_policies = [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=True, identity="Policy1", enable_internal_sender_admin_notifications=False, diff --git a/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py index db84249c10..0b34cc044a 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py @@ -26,11 +26,11 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: defender_malware_policy_notifications_internal_users_malware_enabled, ) from prowler.providers.m365.services.defender.defender_service import ( - DefenderMalwarePolicy, + MalwarePolicy, ) defender_client.malware_policies = [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=True, identity="Default", enable_internal_sender_admin_notifications=False, @@ -76,11 +76,11 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: defender_malware_policy_notifications_internal_users_malware_enabled, ) from prowler.providers.m365.services.defender.defender_service import ( - DefenderMalwarePolicy, + MalwarePolicy, ) defender_client.malware_policies = [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=True, identity="Default", enable_internal_sender_admin_notifications=True, @@ -126,11 +126,11 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: defender_malware_policy_notifications_internal_users_malware_enabled, ) from prowler.providers.m365.services.defender.defender_service import ( - DefenderMalwarePolicy, + MalwarePolicy, ) defender_client.malware_policies = [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=True, identity="Default", enable_internal_sender_admin_notifications=True, diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 3e61bb0673..6a9b881d31 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -6,20 +6,22 @@ from prowler.providers.m365.services.defender.defender_service import ( AntiphishingPolicy, AntiphishingRule, Defender, - DefenderMalwarePolicy, + MalwarePolicy, + OutboundSpamPolicy, + OutboundSpamRule, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider def mock_defender_get_malware_filter_policy(_): return [ - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=False, identity="Policy1", enable_internal_sender_admin_notifications=False, internal_sender_admin_address="", ), - DefenderMalwarePolicy( + MalwarePolicy( enable_file_filter=True, identity="Policy2", enable_internal_sender_admin_notifications=True, @@ -66,6 +68,36 @@ def mock_defender_get_antiphising_rules(_): } +def mock_defender_get_outbound_spam_filter_policy(_): + return { + "Policy1": OutboundSpamPolicy( + notify_sender_blocked=True, + notify_limit_exceeded=True, + notify_limit_exceeded_addresses=["security@example.com"], + notify_sender_blocked_addresses=["security@example.com"], + default=False, + ), + "Policy2": OutboundSpamPolicy( + notify_sender_blocked=False, + notify_limit_exceeded=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=True, + ), + } + + +def mock_defender_get_outbound_spam_filter_rule(_): + return { + "Policy1": OutboundSpamRule( + state="Enabled", + ), + "Policy2": OutboundSpamRule( + state="Disabled", + ), + } + + class Test_Defender_Service: def test_get_client(self): with ( @@ -177,3 +209,57 @@ class Test_Defender_Service: assert antiphishing_rules["Policy1"].state == "Enabled" assert antiphishing_rules["Policy2"].state == "Disabled" defender_client.powershell.close() + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_outbound_spam_filter_policy", + new=mock_defender_get_outbound_spam_filter_policy, + ) + def test_get_outbound_spam_filter_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + outbound_spam_policies = defender_client.outbound_spam_policies + assert outbound_spam_policies["Policy1"].notify_sender_blocked is True + assert outbound_spam_policies["Policy1"].notify_limit_exceeded is True + assert outbound_spam_policies[ + "Policy1" + ].notify_limit_exceeded_addresses == ["security@example.com"] + assert outbound_spam_policies[ + "Policy1" + ].notify_sender_blocked_addresses == ["security@example.com"] + assert outbound_spam_policies["Policy1"].default is False + assert outbound_spam_policies["Policy2"].notify_sender_blocked is False + assert outbound_spam_policies["Policy2"].notify_limit_exceeded is False + assert ( + outbound_spam_policies["Policy2"].notify_limit_exceeded_addresses == [] + ) + assert ( + outbound_spam_policies["Policy2"].notify_sender_blocked_addresses == [] + ) + assert outbound_spam_policies["Policy2"].default is True + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_outbound_spam_filter_rule", + new=mock_defender_get_outbound_spam_filter_rule, + ) + def test_get_outbound_spam_filter_rule(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + outbound_spam_rules = defender_client.outbound_spam_rules + assert outbound_spam_rules["Policy1"].state == "Enabled" + assert outbound_spam_rules["Policy2"].state == "Disabled" From 2478555f0e150711d53d814c9ccb06890f42e5b8 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Tue, 22 Apr 2025 16:06:14 +0200 Subject: [PATCH 192/359] fix(aws): update bucket naming validation to accept dots (#7545) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + prowler/providers/aws/lib/arguments/arguments.py | 5 ++++- tests/lib/cli/parser_test.py | 8 ++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index d42960d4d7..0773aceeef 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -23,6 +23,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Fix package name location in pyproject.toml while replicating for prowler-cloud [(#7531)](https://github.com/prowler-cloud/prowler/pull/7531). - Remove cache in PyPI release action [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532). - Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). +- Update S3 bucket naming validation to accept dots [(#7545)](https://github.com/prowler-cloud/prowler/pull/7545). - Handle new FlowLog model properties in Azure [(#7546)](https://github.com/prowler-cloud/prowler/pull/7546). --- diff --git a/prowler/providers/aws/lib/arguments/arguments.py b/prowler/providers/aws/lib/arguments/arguments.py index 7f0f7872f5..ff5a9ddf77 100644 --- a/prowler/providers/aws/lib/arguments/arguments.py +++ b/prowler/providers/aws/lib/arguments/arguments.py @@ -224,7 +224,10 @@ def validate_arguments(arguments: Namespace) -> tuple[bool, str]: def validate_bucket(bucket_name: str) -> str: """validate_bucket validates that the input bucket_name is valid""" - if search("(?!(^xn--|.+-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$", bucket_name): + if search( + "^(?!^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)(?!.*\.{2})(?!.*\.-)(?!.*-\.)(?!^xn--)(?!^sthree-)(?!^amzn-s3-demo-)(?!.*--table-s3$)[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$", + bucket_name, + ): return bucket_name else: raise ArgumentTypeError( diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index a8f256ef36..1c72443baf 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -1323,9 +1323,11 @@ class Test_Parser: def test_validate_bucket_invalid_bucket_names(self): bad_bucket_names = [ "xn--bucket-name", + "sthree-bucket-name", + "amzn-s3-demo-bucket-name", "mrryadfpcwlscicvnrchmtmyhwrvzkgfgdxnlnvaaummnywciixnzvycnzmhhpwb", "192.168.5.4", - "bucket-name-s3alias", + "bucket-name--table-s3", "bucket-name-s3alias-", "bucket-n$ame", "bu", @@ -1341,7 +1343,9 @@ class Test_Parser: ) def test_validate_bucket_valid_bucket_names(self): - valid_bucket_names = ["bucket-name" "test" "test-test-test"] + valid_bucket_names = [ + "bucket-name" "test" "test-test-test" "test.test.test" "abc" + ] for bucket_name in valid_bucket_names: assert validate_bucket(bucket_name) == bucket_name From 0edf19928269b6d42d1c463ab13b90d7c21a65e4 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 22 Apr 2025 20:13:43 +0545 Subject: [PATCH 193/359] fix(actions): Include files within providers for SDK tests (#7577) --- .github/workflows/sdk-pull-request.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 650e80af63..484df4e10a 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -113,8 +113,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/aws - ./tests/providers/aws + ./prowler/providers/aws/** + ./tests/providers/aws/** - name: AWS - Test if: steps.aws-changed-files.outputs.any_changed == 'true' @@ -127,8 +127,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/azure - ./tests/providers/azure + ./prowler/providers/azure/** + ./tests/providers/azure/** - name: Azure - Test if: steps.azure-changed-files.outputs.any_changed == 'true' @@ -141,8 +141,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/gcp - ./tests/providers/gcp + ./prowler/providers/gcp/** + ./tests/providers/gcp/** - name: GCP - Test if: steps.gcp-changed-files.outputs.any_changed == 'true' @@ -155,8 +155,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/kubernetes - ./tests/providers/kubernetes + ./prowler/providers/kubernetes/** + ./tests/providers/kubernetes/** - name: Kubernetes - Test if: steps.kubernetes-changed-files.outputs.any_changed == 'true' @@ -169,8 +169,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/nhn - ./tests/providers/nhn + ./prowler/providers/nhn/** + ./tests/providers/nhn/** - name: NHN - Test if: steps.nhn-changed-files.outputs.any_changed == 'true' @@ -183,8 +183,8 @@ jobs: uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 with: files: | - ./prowler/providers/m365 - ./tests/providers/m365 + ./prowler/providers/m365/** + ./tests/providers/m365/** - name: M365 - Test if: steps.m365-changed-files.outputs.any_changed == 'true' From a671b092ee143c652d2f9f25ef2ffa066d700b3a Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 22 Apr 2025 17:15:33 +0200 Subject: [PATCH 194/359] feat(defender): add new check `defender_domain_dkim_enabled` (#7485) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 18 +++ .../defender_domain_dkim_enabled/__init__.py | 0 ...defender_domain_dkim_enabled.metadata.json | 30 +++++ .../defender_domain_dkim_enabled.py | 45 +++++++ .../services/defender/defender_service.py | 27 ++++ .../defender_domain_dkim_enabled_test.py | 119 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 30 +++++ 8 files changed, 270 insertions(+) create mode 100644 prowler/providers/m365/services/defender/defender_domain_dkim_enabled/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.py create mode 100644 tests/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 0773aceeef..975b5d978e 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. - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 573cdd5adf..9e40f8e6a3 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -305,3 +305,21 @@ class M365PowerShell(PowerShellSession): } """ return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") + + def get_dkim_config(self) -> dict: + """ + Get DKIM Signing Configuration. + + Retrieves the current DKIM signing configuration settings for Exchange Online. + + Returns: + dict: DKIM signing configuration settings in JSON format. + + Example: + >>> get_dkim_config() + { + "Id": "12345678-1234-1234-1234-123456789012", + "Enabled": true + } + """ + return self.execute("Get-DkimSigningConfig | ConvertTo-Json") diff --git a/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/__init__.py b/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.metadata.json b/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.metadata.json new file mode 100644 index 0000000000..61551723be --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_domain_dkim_enabled", + "CheckTitle": "Ensure that DKIM is enabled for all Exchange Online Domains", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Online Domain", + "Description": "This check ensures that DomainKeys Identified Mail (DKIM) is enabled for all Exchange Online domains. DKIM is a crucial authentication method that, along with SPF and DMARC, helps prevent attackers from sending spoofed emails that appear to originate from your domain. By adding a digital signature to outbound emails, DKIM allows receiving email systems to verify the legitimacy of incoming messages.", + "Risk": "If DKIM is not enabled, attackers may send spoofed emails that appear to originate from your domain, potentially leading to phishing attacks and damage to your domain's reputation.", + "RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/use-dkim-to-validate-outbound-email?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "Set-DkimSigningConfig -Identity -Enabled $True", + "NativeIaC": "", + "Other": "1. After DNS records are created, enable DKIM signing in Microsoft 365 Defender. 2. Navigate to Microsoft 365 Defender at https://security.microsoft.com/. 3. Go to Email & collaboration > Policies & rules > Threat policies. 4. Under Rules, select Email authentication settings. 5. Choose DKIM, click on each domain, and enable 'Sign messages for this domain with DKIM signature'.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable DKIM for all your Exchange Online domains to ensure emails are cryptographically signed and to protect against email spoofing.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-dkimsigningconfig?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.py b/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.py new file mode 100644 index 0000000000..f6258744d0 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled.py @@ -0,0 +1,45 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_domain_dkim_enabled(Check): + """ + Check if DKIM is enabled for all Exchange Online domains. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if DKIM is enabled for all domains. + + This method checks the DKIM signing configuration for each domain to determine if DKIM is enabled. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + for config in defender_client.dkim_configurations: + report = CheckReportM365( + metadata=self.metadata(), + resource=config, + resource_name="DKIM Configuration", + resource_id=config.id, + ) + report.status = "FAIL" + report.status_extended = ( + f"DKIM is not enabled for domain with ID {config.id}." + ) + + if config.dkim_signing_enabled: + report.status = "PASS" + report.status_extended = ( + f"DKIM is enabled for domain with ID {config.id}." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 05e57d669d..3fd256a085 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -16,6 +16,7 @@ class Defender(M365Service): self.outbound_spam_rules = self._get_outbound_spam_filter_rule() self.antiphishing_policies = self._get_antiphising_policy() self.antiphising_rules = self._get_antiphising_rules() + self.dkim_configurations = self._get_dkim_config() self.powershell.close() def _get_malware_filter_policy(self): @@ -93,6 +94,27 @@ class Defender(M365Service): ) return antiphishing_rules + def _get_dkim_config(self): + logger.info("Microsoft365 - Getting DKIM settings...") + dkim_configs = [] + try: + dkim_config = self.powershell.get_dkim_config() + if isinstance(dkim_config, dict): + dkim_config = [dkim_config] + for config in dkim_config: + if config: + dkim_configs.append( + DkimConfig( + dkim_signing_enabled=config.get("Enabled", False), + id=config.get("Id", ""), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return dkim_configs + def _get_outbound_spam_filter_policy(self): logger.info("Microsoft365 - Getting Defender outbound spam filter policy...") outbound_spam_policies = {} @@ -163,6 +185,11 @@ class AntiphishingRule(BaseModel): state: str +class DkimConfig(BaseModel): + dkim_signing_enabled: bool + id: str + + class OutboundSpamPolicy(BaseModel): notify_sender_blocked: bool notify_limit_exceeded: bool diff --git a/tests/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled_test.py b/tests/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled_test.py new file mode 100644 index 0000000000..bbbf82b51c --- /dev/null +++ b/tests/providers/m365/services/defender/defender_domain_dkim_enabled/defender_domain_dkim_enabled_test.py @@ -0,0 +1,119 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_domain_dkim_enabled: + def test_dkim_enabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled import ( + defender_domain_dkim_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DkimConfig, + ) + + defender_client.dkim_configurations = [ + DkimConfig(dkim_signing_enabled=True, id="domain1") + ] + + check = defender_domain_dkim_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "DKIM is enabled for domain with ID domain1." + ) + assert result[0].resource == defender_client.dkim_configurations[0].dict() + assert result[0].resource_name == "DKIM Configuration" + assert result[0].resource_id == "domain1" + assert result[0].location == "global" + + def test_dkim_disabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled import ( + defender_domain_dkim_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DkimConfig, + ) + + defender_client.dkim_configurations = [ + DkimConfig(dkim_signing_enabled=False, id="domain2") + ] + + check = defender_domain_dkim_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "DKIM is not enabled for domain with ID domain2." + ) + assert result[0].resource == defender_client.dkim_configurations[0].dict() + assert result[0].resource_name == "DKIM Configuration" + assert result[0].resource_id == "domain2" + assert result[0].location == "global" + + def test_no_dkim_configurations(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_domain_dkim_enabled.defender_domain_dkim_enabled import ( + defender_domain_dkim_enabled, + ) + + defender_client.dkim_configurations = [] + + check = defender_domain_dkim_enabled() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 6a9b881d31..3738f30a94 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.defender.defender_service import ( AntiphishingPolicy, AntiphishingRule, Defender, + DkimConfig, MalwarePolicy, OutboundSpamPolicy, OutboundSpamRule, @@ -68,6 +69,13 @@ def mock_defender_get_antiphising_rules(_): } +def mock_defender_get_dkim_config(_): + return [ + DkimConfig(dkim_signing_enabled=True, id="domain1"), + DkimConfig(dkim_signing_enabled=False, id="domain2"), + ] + + def mock_defender_get_outbound_spam_filter_policy(_): return { "Policy1": OutboundSpamPolicy( @@ -210,6 +218,28 @@ class Test_Defender_Service: assert antiphishing_rules["Policy2"].state == "Disabled" defender_client.powershell.close() + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_dkim_config", + new=mock_defender_get_dkim_config, + ) + def test_get_dkim_config(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + dkim_configs = defender_client.dkim_configurations + assert dkim_configs[0].dkim_signing_enabled is True + assert dkim_configs[0].id == "domain1" + assert dkim_configs[1].dkim_signing_enabled is False + assert dkim_configs[1].id == "domain2" + defender_client.powershell.close() + @patch( "prowler.providers.m365.services.defender.defender_service.Defender._get_outbound_spam_filter_policy", new=mock_defender_get_outbound_spam_filter_policy, From 30eb78c293f1f309802494dcfe59903d0fa2aabd Mon Sep 17 00:00:00 2001 From: Matt Keeler <19890779+mattkeeler@users.noreply.github.com> Date: Tue, 22 Apr 2025 12:24:12 -0400 Subject: [PATCH 195/359] fix(aws): use correct ports in `ec2_instance_port_cifs_exposed_to_internet` recommendation (#7574) Co-authored-by: MrCloudSec --- .../ec2_instance_port_cifs_exposed_to_internet.metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler/providers/aws/services/ec2/ec2_instance_port_cifs_exposed_to_internet/ec2_instance_port_cifs_exposed_to_internet.metadata.json b/prowler/providers/aws/services/ec2/ec2_instance_port_cifs_exposed_to_internet/ec2_instance_port_cifs_exposed_to_internet.metadata.json index bc34ca0804..c37e3752c3 100644 --- a/prowler/providers/aws/services/ec2/ec2_instance_port_cifs_exposed_to_internet/ec2_instance_port_cifs_exposed_to_internet.metadata.json +++ b/prowler/providers/aws/services/ec2/ec2_instance_port_cifs_exposed_to_internet/ec2_instance_port_cifs_exposed_to_internet.metadata.json @@ -21,7 +21,7 @@ "Terraform": "" }, "Recommendation": { - "Text": "Modify the security group to remove the rule that allows ingress from the internet to TCP port 389 or 636 (LDAP).", + "Text": "Modify the security group to remove the rule that allows ingress from the internet to TCP port 139 or 445 (CIFS).", "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" } }, From d816d73174354950c3601c960d89683f20259aa7 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:28:18 +0200 Subject: [PATCH 196/359] feat(defender): add new check `defender_antispam_connection_filter_policy_empty_ip_allowlist` (#7492) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 20 +++ .../__init__.py | 0 ...er_policy_empty_ip_allowlist.metadata.json | 30 +++++ ...ection_filter_policy_empty_ip_allowlist.py | 43 ++++++ .../services/defender/defender_service.py | 22 ++++ ...n_filter_policy_empty_ip_allowlist_test.py | 124 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 28 ++++ 8 files changed, 268 insertions(+) create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py create mode 100644 tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 975b5d978e..210a5003d8 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. - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 9e40f8e6a3..b248bd30bd 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -306,6 +306,26 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") + def get_connection_filter_policy(self) -> dict: + """ + Get Exchange Online Connection Filter Policy. + + Retrieves the current connection filter policy settings for Exchange Online. + + Returns: + dict: Connection filter policy settings in JSON format. + + Example: + >>> get_connection_filter_policy() + { + "Identity": "Default", + "IPAllowList": []" + } + """ + return self.execute( + "Get-HostedConnectionFilterPolicy -Identity Default | ConvertTo-Json" + ) + def get_dkim_config(self) -> dict: """ Get DKIM Signing Configuration. diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/__init__.py b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.metadata.json b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.metadata.json new file mode 100644 index 0000000000..9b46539a82 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_antispam_connection_filter_policy_empty_ip_allowlist", + "CheckTitle": "Ensure the Anti-Spam Connection Filter Policy IP Allowlist is empty or undefined.", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Defender Anti-Spam Policy", + "Description": "This check focuses on Microsoft 365 organizations with Exchange Online mailboxes or standalone Exchange Online Protection (EOP) organizations. It ensures that the connection filter policy's IP Allowlist is empty or undefined to prevent bypassing spam filtering and sender authentication checks, which could lead to successful delivery of malicious emails.", + "Risk": "Using the IP Allowlist without additional verification like mail flow rules poses a risk, as emails from these sources skip essential security checks (SPF, DKIM, DMARC). This could allow attackers to deliver harmful emails directly to the Inbox.", + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "Set-HostedConnectionFilterPolicy -Identity Default -IPAllowList @{}", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules. 3. On the Policies & rules page select Threat policies. 4. Under Policies, select Anti-spam and click on the Connection filter policy (Default). 5. Remove IP entries from the allow list. 6. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that the IP Allowlist in your connection filter policy is empty or undefined to prevent bypassing essential security checks.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-hostedconnectionfilterpolicy?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py new file mode 100644 index 0000000000..054195ae7a --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py @@ -0,0 +1,43 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_antispam_connection_filter_policy_empty_ip_allowlist(Check): + """ + Check if the IP Allowlist is not used in the Defender connection filter policy. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if the IP Allowlist is not used. + + This method checks the Defender connection filter policy to determine if the + IP Allowlist is empty or undefined. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + policy = defender_client.connection_filter_policy + if policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Antispam Connection Filter Policy", + resource_id=policy.identity, + ) + report.status = "PASS" + report.status_extended = f"IP Allowlist is not used in the Antispam Connection Filter Policy {policy.identity}." + + if policy.ip_allow_list: + report.status = "FAIL" + report.status_extended = f"IP Allowlist is used in the Antispam Connection Filter Policy {policy.identity} with IPs: {policy.ip_allow_list}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 3fd256a085..1528dcd4b0 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -16,6 +16,7 @@ class Defender(M365Service): self.outbound_spam_rules = self._get_outbound_spam_filter_rule() self.antiphishing_policies = self._get_antiphising_policy() self.antiphising_rules = self._get_antiphising_rules() + self.connection_filter_policy = self._get_connection_filter_policy() self.dkim_configurations = self._get_dkim_config() self.powershell.close() @@ -94,6 +95,22 @@ class Defender(M365Service): ) return antiphishing_rules + def _get_connection_filter_policy(self): + logger.info("Microsoft365 - Getting connection filter policy...") + connection_filter_policy = None + try: + policy = self.powershell.get_connection_filter_policy() + if policy: + connection_filter_policy = ConnectionFilterPolicy( + ip_allow_list=policy.get("IPAllowList", []), + identity=policy.get("Identity", ""), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return connection_filter_policy + def _get_dkim_config(self): logger.info("Microsoft365 - Getting DKIM settings...") dkim_configs = [] @@ -185,6 +202,11 @@ class AntiphishingRule(BaseModel): state: str +class ConnectionFilterPolicy(BaseModel): + ip_allow_list: list + identity: str + + class DkimConfig(BaseModel): dkim_signing_enabled: bool id: str diff --git a/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py new file mode 100644 index 0000000000..e4dfeb772b --- /dev/null +++ b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py @@ -0,0 +1,124 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_antispam_connection_filter_policy_empty_ip_allowlist: + def test_ip_allow_list_not_used(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist import ( + defender_antispam_connection_filter_policy_empty_ip_allowlist, + ) + from prowler.providers.m365.services.defender.defender_service import ( + ConnectionFilterPolicy, + ) + + defender_client.connection_filter_policy = ConnectionFilterPolicy( + ip_allow_list=[], + identity="Default", + ) + + check = defender_antispam_connection_filter_policy_empty_ip_allowlist() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "IP Allowlist is not used in the Antispam Connection Filter Policy Default." + ) + assert result[0].resource == defender_client.connection_filter_policy.dict() + assert ( + result[0].resource_name == "Defender Antispam Connection Filter Policy" + ) + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_ip_allow_list_used(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist import ( + defender_antispam_connection_filter_policy_empty_ip_allowlist, + ) + from prowler.providers.m365.services.defender.defender_service import ( + ConnectionFilterPolicy, + ) + + defender_client.connection_filter_policy = ConnectionFilterPolicy( + ip_allow_list=["192.168.0.1", "10.0.0.5"], + identity="Default", + ) + + check = defender_antispam_connection_filter_policy_empty_ip_allowlist() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "IP Allowlist is used in the Antispam Connection Filter Policy Default with IPs: ['192.168.0.1', '10.0.0.5']." + ) + assert result[0].resource == defender_client.connection_filter_policy.dict() + assert ( + result[0].resource_name == "Defender Antispam Connection Filter Policy" + ) + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_no_connection_filter_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_empty_ip_allowlist.defender_antispam_connection_filter_policy_empty_ip_allowlist import ( + defender_antispam_connection_filter_policy_empty_ip_allowlist, + ) + + defender_client.connection_filter_policy = None + + check = defender_antispam_connection_filter_policy_empty_ip_allowlist() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 3738f30a94..2d3de6e0f6 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -5,6 +5,7 @@ from prowler.providers.m365.models import M365IdentityInfo from prowler.providers.m365.services.defender.defender_service import ( AntiphishingPolicy, AntiphishingRule, + ConnectionFilterPolicy, Defender, DkimConfig, MalwarePolicy, @@ -69,6 +70,13 @@ def mock_defender_get_antiphising_rules(_): } +def mock_defender_get_connection_filter_policy(_): + return ConnectionFilterPolicy( + ip_allow_list=[], + identity="Default", + ) + + def mock_defender_get_dkim_config(_): return [ DkimConfig(dkim_signing_enabled=True, id="domain1"), @@ -218,6 +226,26 @@ class Test_Defender_Service: assert antiphishing_rules["Policy2"].state == "Disabled" defender_client.powershell.close() + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_connection_filter_policy", + new=mock_defender_get_connection_filter_policy, + ) + def test__get_connection_filter_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + connection_filter_policy = defender_client.connection_filter_policy + assert connection_filter_policy.ip_allow_list == [] + assert connection_filter_policy.identity == "Default" + defender_client.powershell.close() + @patch( "prowler.providers.m365.services.defender.defender_service.Defender._get_dkim_config", new=mock_defender_get_dkim_config, From 098382117e7b042bbcc72dc3ebde77a6db765508 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:52:34 +0200 Subject: [PATCH 197/359] feat(defender): add new check `defender_antispam_connection_filter_policy_safe_list_off` (#7494) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + ...ection_filter_policy_empty_ip_allowlist.py | 4 +- .../__init__.py | 0 ..._filter_policy_safe_list_off.metadata.json | 30 ++++ ..._connection_filter_policy_safe_list_off.py | 43 ++++++ .../services/defender/defender_service.py | 2 + ...n_filter_policy_empty_ip_allowlist_test.py | 2 + ...ection_filter_policy_safe_list_off_test.py | 128 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 2 + 9 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.py create mode 100644 tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 210a5003d8..1d0c4f2887 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) +- Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) ### Fixed diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py index 054195ae7a..00ace7b17a 100644 --- a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py +++ b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist.py @@ -6,7 +6,7 @@ from prowler.providers.m365.services.defender.defender_client import defender_cl class defender_antispam_connection_filter_policy_empty_ip_allowlist(Check): """ - Check if the IP Allowlist is not used in the Defender connection filter policy. + Check if the IP Allowlist is not used in the Antispam Connection Filter Policy. Attributes: metadata: Metadata associated with the check (inherited from Check). @@ -16,7 +16,7 @@ class defender_antispam_connection_filter_policy_empty_ip_allowlist(Check): """ Execute the check to verify if the IP Allowlist is not used. - This method checks the Defender connection filter policy to determine if the + This method checks the Antispam Connection Filter Policy to determine if the IP Allowlist is empty or undefined. Returns: diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/__init__.py b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.metadata.json b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.metadata.json new file mode 100644 index 0000000000..cf7234e5da --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_antispam_connection_filter_policy_safe_list_off", + "CheckTitle": "Ensure the default connection filter policy has the SafeList setting disabled", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Defender Anti-Spam Policy", + "Description": "This check ensures that the EnableSafeList setting in the default connection filter policy is set to False. The safe list, managed dynamically by Microsoft, allows emails from listed IPs to bypass spam filtering and sender authentication checks, posing a security risk.", + "Risk": "If the safe list is enabled, emails from IPs on this list can bypass essential security checks (SPF, DKIM, DMARC), potentially allowing malicious emails to be delivered directly to users' inboxes.", + "RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/connection-filter-policies-configure", + "Remediation": { + "Code": { + "CLI": "Set-HostedConnectionFilterPolicy -Identity Default -EnableSafeList $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules. 3. On the Policies & rules page select Threat policies. 4. Under Policies, select Anti-spam and click on the Connection filter policy (Default). 5. Disable the safe list option. 6. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that the EnableSafeList setting in your connection filter policy is set to False to prevent bypassing essential security checks.", + "Url": "https://learn.microsoft.com/en-us/defender-office-365/create-safe-sender-lists-in-office-365#use-the-ip-allow-list" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.py b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.py new file mode 100644 index 0000000000..7989cefd8c --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off.py @@ -0,0 +1,43 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_antispam_connection_filter_policy_safe_list_off(Check): + """ + Check if the Safe List is off in the Antispam Connection Filter Policy. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if the Safe List is off. + + This method checks the Antispam Connection Filter Policy to determine if the + Safe List is disabled. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + policy = defender_client.connection_filter_policy + if policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Antispam Connection Filter Policy", + resource_id=policy.identity, + ) + report.status = "PASS" + report.status_extended = f"Safe List is disabled in the Antispam Connection Filter Policy {policy.identity}." + + if policy.enable_safe_list: + report.status = "FAIL" + report.status_extended = f"Safe List is not disabled in the Antispam Connection Filter Policy {policy.identity}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 1528dcd4b0..51f53a0606 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -104,6 +104,7 @@ class Defender(M365Service): connection_filter_policy = ConnectionFilterPolicy( ip_allow_list=policy.get("IPAllowList", []), identity=policy.get("Identity", ""), + enable_safe_list=policy.get("EnableSafeList", False), ) except Exception as error: logger.error( @@ -205,6 +206,7 @@ class AntiphishingRule(BaseModel): class ConnectionFilterPolicy(BaseModel): ip_allow_list: list identity: str + enable_safe_list: bool class DkimConfig(BaseModel): diff --git a/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py index e4dfeb772b..83f10ccea9 100644 --- a/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_empty_ip_allowlist/defender_antispam_connection_filter_policy_empty_ip_allowlist_test.py @@ -32,6 +32,7 @@ class Test_defender_antispam_connection_filter_policy_empty_ip_allowlist: defender_client.connection_filter_policy = ConnectionFilterPolicy( ip_allow_list=[], identity="Default", + enable_safe_list=False, ) check = defender_antispam_connection_filter_policy_empty_ip_allowlist() @@ -78,6 +79,7 @@ class Test_defender_antispam_connection_filter_policy_empty_ip_allowlist: defender_client.connection_filter_policy = ConnectionFilterPolicy( ip_allow_list=["192.168.0.1", "10.0.0.5"], identity="Default", + enable_safe_list=False, ) check = defender_antispam_connection_filter_policy_empty_ip_allowlist() diff --git a/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off_test.py b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off_test.py new file mode 100644 index 0000000000..239f5aaf2f --- /dev/null +++ b/tests/providers/m365/services/defender/defender_antispam_connection_filter_policy_safe_list_off/defender_antispam_connection_filter_policy_safe_list_off_test.py @@ -0,0 +1,128 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_antispam_connection_filter_policy_safe_list_off: + def test_safe_list_off(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off import ( + defender_antispam_connection_filter_policy_safe_list_off, + ) + from prowler.providers.m365.services.defender.defender_service import ( + ConnectionFilterPolicy, + ) + + defender_client.connection_filter_policy = ConnectionFilterPolicy( + ip_allow_list=[], + identity="Default", + enable_safe_list=False, + ) + + check = defender_antispam_connection_filter_policy_safe_list_off() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Safe List is disabled in the Antispam Connection Filter Policy Default." + ) + assert result[0].resource == defender_client.connection_filter_policy.dict() + assert ( + result[0].resource_name == "Defender Antispam Connection Filter Policy" + ) + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_safe_list_on(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off import ( + defender_antispam_connection_filter_policy_safe_list_off, + ) + from prowler.providers.m365.services.defender.defender_service import ( + ConnectionFilterPolicy, + ) + + defender_client.connection_filter_policy = ConnectionFilterPolicy( + ip_allow_list=[], + identity="Default", + enable_safe_list=True, + ) + + check = defender_antispam_connection_filter_policy_safe_list_off() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Safe List is not disabled in the Antispam Connection Filter Policy Default." + ) + assert result[0].resource == defender_client.connection_filter_policy.dict() + assert ( + result[0].resource_name == "Defender Antispam Connection Filter Policy" + ) + assert result[0].resource_id == "Default" + assert result[0].location == "global" + + def test_no_connection_filter_policy(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_connection_filter_policy_safe_list_off.defender_antispam_connection_filter_policy_safe_list_off import ( + defender_antispam_connection_filter_policy_safe_list_off, + ) + + defender_client.connection_filter_policy = None + + check = defender_antispam_connection_filter_policy_safe_list_off() + result = check.execute() + + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 2d3de6e0f6..28d9d47919 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -74,6 +74,7 @@ def mock_defender_get_connection_filter_policy(_): return ConnectionFilterPolicy( ip_allow_list=[], identity="Default", + enable_safe_list=False, ) @@ -244,6 +245,7 @@ class Test_Defender_Service: connection_filter_policy = defender_client.connection_filter_policy assert connection_filter_policy.ip_allow_list == [] assert connection_filter_policy.identity == "Default" + assert connection_filter_policy.enable_safe_list is False defender_client.powershell.close() @patch( From 29fefba62ef85d73664cc2858e5f130822a5492a Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:57:18 +0200 Subject: [PATCH 198/359] fix(teams): `teams_email_sending_to_channel_disabled` docstrings (#7559) --- .../teams_email_sending_to_channel_disabled.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py index bcf4eec9b8..915840ff1c 100644 --- a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py +++ b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py @@ -5,7 +5,7 @@ from prowler.providers.m365.services.teams.teams_client import teams_client class teams_email_sending_to_channel_disabled(Check): - """Check if + """Check if users can send emails to channel email addresses. Attributes: metadata: Metadata associated with the check (inherited from Check). @@ -14,7 +14,7 @@ class teams_email_sending_to_channel_disabled(Check): def execute(self) -> List[CheckReportM365]: """Execute the check for - This method checks if + This method checks if users can send emails to channel email addresses. Returns: List[CheckReportM365]: A list of reports containing the result of the check. From 2379544425d243130a023282af7e80d1cb0a3063 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 22 Apr 2025 19:04:51 +0200 Subject: [PATCH 199/359] feat(teams): add new check `teams_external_domains_restricted` (#7557) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 17 +++ .../__init__.py | 0 ..._external_domains_restricted.metadata.json | 30 +++++ .../teams_external_domains_restricted.py | 40 +++++++ .../m365/services/teams/teams_service.py | 20 ++++ .../teams_external_domains_restricted_test.py | 106 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 27 +++++ 8 files changed, 241 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_external_domains_restricted/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.py create mode 100644 tests/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 1d0c4f2887..8c4cad0e15 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408) - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) +- Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index b248bd30bd..3785bac7f5 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -137,6 +137,23 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-CsTeamsClientConfiguration | ConvertTo-Json") + def get_user_settings(self) -> dict: + """ + Get Teams User Settings. + + Retrieves the current Microsoft Teams user settings. + + Returns: + dict: Teams user settings in JSON format. + + Example: + >>> get_user_settings() + { + "AllowExternalAccess": true + } + """ + return self.execute("Get-CsTenantFederationConfiguration | ConvertTo-Json") + def connect_exchange_online(self) -> dict: """ Connect to Exchange Online PowerShell Module. diff --git a/prowler/providers/m365/services/teams/teams_external_domains_restricted/__init__.py b/prowler/providers/m365/services/teams/teams_external_domains_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.metadata.json b/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.metadata.json new file mode 100644 index 0000000000..ded2210078 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_external_domains_restricted", + "CheckTitle": "Ensure external domains are restricted.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Settings", + "Description": "Ensure external domains are restricted from being used in Teams admin center.", + "Risk": "Allowing unrestricted communication with external domains in Microsoft Teams increases the risk of exposure to social engineering attacks, phishing, malware delivery (e.g., DarkGate), and exploitation tactics such as GIFShell or username enumeration.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTenantFederationConfiguration -AllowFederatedUsers $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com/. 2. Click to expand Users select External access. 3. Under Teams and Skype for Business users in external organizations set Choose which external domains your users have access to to one of the following: Allow only specific external domains or Block all external domains. 4. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict external collaboration by configuring Teams to either Block all external domains or Allow only specific, trusted external domains. This ensures users can only interact with vetted organizations, significantly reducing the attack surface.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.py b/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.py new file mode 100644 index 0000000000..f2f2d0bae4 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted.py @@ -0,0 +1,40 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_external_domains_restricted(Check): + """Check if external domains are restricted from being used in Teams admin center. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for + + This method checks if external domains are restricted from being used in Teams admin center. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + user_settings = teams_client.user_settings + if user_settings: + report = CheckReportM365( + metadata=self.metadata(), + resource=user_settings if user_settings else {}, + resource_name="Teams User Settings", + resource_id="userSettings", + ) + report.status = "FAIL" + report.status_extended = "Users can access external domains." + + if user_settings and not user_settings.allow_external_access: + report.status = "PASS" + report.status_extended = "Users can not access external domains." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 1fb71c7740..ef758e9677 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -10,6 +10,7 @@ class Teams(M365Service): super().__init__(provider) self.powershell.connect_microsoft_teams() self.teams_settings = self._get_teams_client_configuration() + self.user_settings = self._get_user_settings() self.powershell.close() def _get_teams_client_configuration(self): @@ -37,6 +38,21 @@ class Teams(M365Service): ) return teams_settings + def _get_user_settings(self): + logger.info("M365 - Getting Teams user settings...") + user_settings = None + try: + settings = self.powershell.get_user_settings() + if settings: + user_settings = UserSettings( + allow_external_access=settings.get("AllowFederatedUsers", True), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return user_settings + class CloudStorageSettings(BaseModel): allow_box: bool @@ -49,3 +65,7 @@ class CloudStorageSettings(BaseModel): class TeamsSettings(BaseModel): cloud_storage_settings: CloudStorageSettings allow_email_into_channel: bool = True + + +class UserSettings(BaseModel): + allow_external_access: bool = True diff --git a/tests/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted_test.py b/tests/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted_test.py new file mode 100644 index 0000000000..e85d9fd6bd --- /dev/null +++ b/tests/providers/m365/services/teams/teams_external_domains_restricted/teams_external_domains_restricted_test.py @@ -0,0 +1,106 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_external_domains_restricted: + def test_no_user_settings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + teams_client.user_settings = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import ( + teams_external_domains_restricted, + ) + + check = teams_external_domains_restricted() + result = check.execute() + assert len(result) == 0 + + def test_external_domains_allowed(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import ( + teams_external_domains_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import UserSettings + + teams_client.user_settings = UserSettings( + allow_external_access=True, + ) + + check = teams_external_domains_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == "Users can access external domains." + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" + + def test_external_domains_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import ( + teams_external_domains_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import UserSettings + + teams_client.user_settings = UserSettings( + allow_external_access=False, + ) + + check = teams_external_domains_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == "Users can not access external domains." + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index 73d6425433..d20a696432 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.teams.teams_service import ( CloudStorageSettings, Teams, TeamsSettings, + UserSettings, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -22,6 +23,12 @@ def mock_get_teams_client_configuration(_): ) +def mock_get_user_settings(_): + return UserSettings( + allow_external_access=False, + ) + + class Test_Teams_Service: def test_get_client(self): with ( @@ -63,3 +70,23 @@ class Test_Teams_Service: ) ) teams_client.powershell.close() + + @patch( + "prowler.providers.m365.services.teams.teams_service.Teams._get_user_settings", + new=mock_get_user_settings, + ) + def test_get_user_settings(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + ): + teams_client = Teams( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert teams_client.user_settings == UserSettings( + allow_external_access=False, + ) + teams_client.powershell.close() From cbaddad358c95491e28b1ace483f8b663a71a376 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 22 Apr 2025 19:25:30 +0200 Subject: [PATCH 200/359] feat(teams): add new check `teams_unmanaged_communication_disabled` (#7561) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/services/teams/teams_service.py | 2 + .../__init__.py | 0 ...naged_communication_disabled.metadata.json | 30 +++++ .../teams_unmanaged_communication_disabled.py | 42 +++++++ .../m365/services/teams/teams_service_test.py | 5 +- ...s_unmanaged_communication_disabled_test.py | 112 ++++++++++++++++++ 7 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 8c4cad0e15..f903a3024d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561) - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index ef758e9677..c082bd4dc4 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -46,6 +46,7 @@ class Teams(M365Service): if settings: user_settings = UserSettings( allow_external_access=settings.get("AllowFederatedUsers", True), + allow_teams_consumer=settings.get("AllowTeamsConsumer", True), ) except Exception as error: logger.error( @@ -69,3 +70,4 @@ class TeamsSettings(BaseModel): class UserSettings(BaseModel): allow_external_access: bool = True + allow_teams_consumer: bool = True diff --git a/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.metadata.json new file mode 100644 index 0000000000..07233d8eac --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_unmanaged_communication_disabled", + "CheckTitle": "Ensure unmanaged communication is disabled.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Settings", + "Description": "Ensure unmanaged communication is disabled in Teams admin center.", + "Risk": "Allowing communication with unmanaged Microsoft Teams users increases the risk of targeted attacks such as phishing, malware distribution (e.g., DarkGate), and exploitation techniques like GIFShell and username enumeration. Unmanaged accounts are easier for threat actors to create and use as attack vectors.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTenantFederationConfiguration -AllowTeamsConsumer $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com/. 2. Click to expand Users select External access. 3. Scroll to Teams accounts not managed by an organization. 4. Set People in my organization can communicate with Teams users whose accounts aren't managed by an organization to Off. 5. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable communication with Teams users whose accounts aren't managed by an organization by setting 'People in my organization can communicate with Teams users whose accounts aren't managed by an organization' to Off. This helps prevent unauthorized or risky external interactions.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py new file mode 100644 index 0000000000..9672cd88bb --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_unmanaged_communication_disabled(Check): + """Check if unmanaged communication is disabled in Teams admin center. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for + + This method checks if unmanaged communication is disabled in Teams admin center. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + user_settings = teams_client.user_settings + if user_settings: + report = CheckReportM365( + metadata=self.metadata(), + resource=user_settings if user_settings else {}, + resource_name="Teams User Settings", + resource_id="userSettings", + ) + report.status = "FAIL" + report.status_extended = "Users can communicate with unmanaged users." + + if user_settings and not user_settings.allow_teams_consumer: + report.status = "PASS" + report.status_extended = ( + "Users can not communicate with unmanaged users." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index d20a696432..5cc8a59e89 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -26,6 +26,7 @@ def mock_get_teams_client_configuration(_): def mock_get_user_settings(_): return UserSettings( allow_external_access=False, + allow_teams_consumer=False, ) @@ -67,7 +68,8 @@ class Test_Teams_Service: allow_egnyte=False, allow_google_drive=False, allow_share_file=False, - ) + ), + allow_email_into_channel=True, ) teams_client.powershell.close() @@ -88,5 +90,6 @@ class Test_Teams_Service: ) assert teams_client.user_settings == UserSettings( allow_external_access=False, + allow_teams_consumer=False, ) teams_client.powershell.close() diff --git a/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py b/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py new file mode 100644 index 0000000000..cde835de41 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py @@ -0,0 +1,112 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_unmanaged_communication_disabled: + def test_no_user_settings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + teams_client.user_settings = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import ( + teams_unmanaged_communication_disabled, + ) + + check = teams_unmanaged_communication_disabled() + result = check.execute() + assert len(result) == 0 + + def test_unmanaged_communication_allowed(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_service import UserSettings + from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import ( + teams_unmanaged_communication_disabled, + ) + + teams_client.user_settings = UserSettings( + allow_teams_consumer=True, + ) + + check = teams_unmanaged_communication_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Users can communicate with unmanaged users." + ) + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" + + def test_unmanaged_communication_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_service import UserSettings + from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import ( + teams_unmanaged_communication_disabled, + ) + + teams_client.user_settings = UserSettings( + allow_teams_consumer=False, + ) + + check = teams_unmanaged_communication_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Users can not communicate with unmanaged users." + ) + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" From 8713b74204ff0682b0986adf09666d8a5cf01a1c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 22 Apr 2025 20:36:54 +0200 Subject: [PATCH 201/359] feat(teams): add new check `teams_external_users_cannot_start_conversations` (#7562) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + ...teams_email_sending_to_channel_disabled.py | 6 +- .../__init__.py | 0 ...s_cannot_start_conversations.metadata.json | 30 +++++ ...ternal_users_cannot_start_conversations.py | 42 +++++++ .../m365/services/teams/teams_service.py | 4 + .../teams_unmanaged_communication_disabled.py | 6 +- ..._email_sending_to_channel_disabled_test.py | 4 +- ...l_users_cannot_start_conversations_test.py | 112 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + ...s_unmanaged_communication_disabled_test.py | 4 +- 11 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.py create mode 100644 tests/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f903a3024d..8426aa3e17 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) - Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561) +- Add new check `teams_external_users_cannot_start_conversations` [(#7562)](https://github.com/prowler-cloud/prowler/pull/7562) - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) diff --git a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py index 915840ff1c..6a473daf96 100644 --- a/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py +++ b/prowler/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled.py @@ -29,12 +29,14 @@ class teams_email_sending_to_channel_disabled(Check): resource_id="teamsSettings", ) report.status = "FAIL" - report.status_extended = "Users can send emails to channel email addresses." + report.status_extended = ( + "Teams users can send emails to channel email addresses." + ) if teams_settings and not teams_settings.allow_email_into_channel: report.status = "PASS" report.status_extended = ( - "Users can not send emails to channel email addresses." + "Teams users cannot send emails to channel email addresses." ) findings.append(report) diff --git a/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/__init__.py b/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.metadata.json b/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.metadata.json new file mode 100644 index 0000000000..8f95019c66 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_external_users_cannot_start_conversations", + "CheckTitle": "Ensure external users cannot start conversations.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Settings", + "Description": "Ensure external users cannot initiate conversations.", + "Risk": "Allowing unmanaged external Teams users to initiate conversations increases the risk of phishing, malware distribution such as DarkGate, social engineering attacks like those by Midnight Blizzard, GIFShell exploitation, and username enumeration.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTenantFederationConfiguration -AllowTeamsConsumerInbound $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com/. 2. Click to expand Users select External access. 3. Scroll to Teams accounts not managed by an organization. 4. Uncheck External users with Teams accounts not managed by an organization can contact users in my organization. 5. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable the ability for external Teams users not managed by an organization to initiate conversations by unchecking the option that permits them to contact users in your organization. This provides an added layer of protection, especially if exceptions are made to allow limited communication with unmanaged users.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.py b/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.py new file mode 100644 index 0000000000..863c026383 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_external_users_cannot_start_conversations(Check): + """Check if external users cannot start conversations. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for external users cannot start conversations. + + This method checks if external users cannot start conversations. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + user_settings = teams_client.user_settings + if user_settings: + report = CheckReportM365( + metadata=self.metadata(), + resource=user_settings if user_settings else {}, + resource_name="Teams User Settings", + resource_id="userSettings", + ) + report.status = "FAIL" + report.status_extended = "External Teams users can initiate conversations." + + if user_settings and not user_settings.allow_teams_consumer_inbound: + report.status = "PASS" + report.status_extended = ( + "External Teams users cannot initiate conversations." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index c082bd4dc4..9d1810e437 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -47,6 +47,9 @@ class Teams(M365Service): user_settings = UserSettings( allow_external_access=settings.get("AllowFederatedUsers", True), allow_teams_consumer=settings.get("AllowTeamsConsumer", True), + allow_teams_consumer_inbound=settings.get( + "AllowTeamsConsumerInbound", True + ), ) except Exception as error: logger.error( @@ -71,3 +74,4 @@ class TeamsSettings(BaseModel): class UserSettings(BaseModel): allow_external_access: bool = True allow_teams_consumer: bool = True + allow_teams_consumer_inbound: bool = True diff --git a/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py index 9672cd88bb..dc8e377ecf 100644 --- a/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py +++ b/prowler/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled.py @@ -12,7 +12,7 @@ class teams_unmanaged_communication_disabled(Check): """ def execute(self) -> List[CheckReportM365]: - """Execute the check for + """Execute the check for unmanaged communication disabled. This method checks if unmanaged communication is disabled in Teams admin center. @@ -29,12 +29,12 @@ class teams_unmanaged_communication_disabled(Check): resource_id="userSettings", ) report.status = "FAIL" - report.status_extended = "Users can communicate with unmanaged users." + report.status_extended = "Teams users can communicate with unmanaged users." if user_settings and not user_settings.allow_teams_consumer: report.status = "PASS" report.status_extended = ( - "Users can not communicate with unmanaged users." + "Teams users cannot communicate with unmanaged users." ) findings.append(report) diff --git a/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py b/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py index 7ee0a6a61d..3d1702e5ae 100644 --- a/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py +++ b/tests/providers/m365/services/teams/teams_email_sending_to_channel_disabled/teams_email_sending_to_channel_disabled_test.py @@ -47,7 +47,7 @@ class Test_teams_email_sending_to_channel_disabled: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Users can send emails to channel email addresses." + == "Teams users can send emails to channel email addresses." ) assert result[0].resource == teams_client.teams_settings.dict() assert result[0].resource_name == "Teams Settings" @@ -97,7 +97,7 @@ class Test_teams_email_sending_to_channel_disabled: assert result[0].status == "PASS" assert ( result[0].status_extended - == "Users can not send emails to channel email addresses." + == "Teams users cannot send emails to channel email addresses." ) assert result[0].resource == teams_client.teams_settings.dict() assert result[0].resource_name == "Teams Settings" diff --git a/tests/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations_test.py b/tests/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations_test.py new file mode 100644 index 0000000000..6b5dd1dff0 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_external_users_cannot_start_conversations/teams_external_users_cannot_start_conversations_test.py @@ -0,0 +1,112 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_external_users_cannot_start_conversations: + def test_no_user_settings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + teams_client.user_settings = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import ( + teams_external_users_cannot_start_conversations, + ) + + check = teams_external_users_cannot_start_conversations() + result = check.execute() + assert len(result) == 0 + + def test_unmanaged_communication_allowed(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import ( + teams_external_users_cannot_start_conversations, + ) + from prowler.providers.m365.services.teams.teams_service import UserSettings + + teams_client.user_settings = UserSettings( + allow_teams_consumer_inbound=True, + ) + + check = teams_external_users_cannot_start_conversations() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External Teams users can initiate conversations." + ) + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" + + def test_unmanaged_communication_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import ( + teams_external_users_cannot_start_conversations, + ) + from prowler.providers.m365.services.teams.teams_service import UserSettings + + teams_client.user_settings = UserSettings( + allow_teams_consumer_inbound=False, + ) + + check = teams_external_users_cannot_start_conversations() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External Teams users cannot initiate conversations." + ) + assert result[0].resource == teams_client.user_settings.dict() + assert result[0].resource_name == "Teams User Settings" + assert result[0].resource_id == "userSettings" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index 5cc8a59e89..41874155d5 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -27,6 +27,7 @@ def mock_get_user_settings(_): return UserSettings( allow_external_access=False, allow_teams_consumer=False, + allow_teams_consumer_inbound=False, ) @@ -91,5 +92,6 @@ class Test_Teams_Service: assert teams_client.user_settings == UserSettings( allow_external_access=False, allow_teams_consumer=False, + allow_teams_consumer_inbound=False, ) teams_client.powershell.close() diff --git a/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py b/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py index cde835de41..2e46ac8efc 100644 --- a/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py +++ b/tests/providers/m365/services/teams/teams_unmanaged_communication_disabled/teams_unmanaged_communication_disabled_test.py @@ -64,7 +64,7 @@ class Test_teams_unmanaged_communication_disabled: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Users can communicate with unmanaged users." + == "Teams users can communicate with unmanaged users." ) assert result[0].resource == teams_client.user_settings.dict() assert result[0].resource_name == "Teams User Settings" @@ -104,7 +104,7 @@ class Test_teams_unmanaged_communication_disabled: assert result[0].status == "PASS" assert ( result[0].status_extended - == "Users can not communicate with unmanaged users." + == "Teams users cannot communicate with unmanaged users." ) assert result[0].resource == teams_client.user_settings.dict() assert result[0].resource_name == "Teams User Settings" From 0234957907e6acd01ae1f7b6e1dd6ce5eec61b6f Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:02:16 +0200 Subject: [PATCH 202/359] feat(teams): add new check `teams_meeting_anonymous_user_join_disabled` (#7565) Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 19 +++ .../__init__.py | 0 ...anonymous_user_join_disabled.metadata.json | 30 +++++ ...ms_meeting_anonymous_user_join_disabled.py | 40 ++++++ .../m365/services/teams/teams_service.py | 22 ++++ ...eting_anonymous_user_join_disabled_test.py | 117 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 25 ++++ 8 files changed, 254 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 8426aa3e17..6c8ffb5b0d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check `teams_meeting_anonymous_user_join_disabled` [(#7565)](https://github.com/prowler-cloud/prowler/pull/7565) - Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561) - Add new check `teams_external_users_cannot_start_conversations` [(#7562)](https://github.com/prowler-cloud/prowler/pull/7562) - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 3785bac7f5..7b272cc748 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -137,6 +137,25 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-CsTeamsClientConfiguration | ConvertTo-Json") + def get_global_meeting_policy(self) -> dict: + """ + Get Teams Global Meeting Policy. + + Retrieves the current Microsoft Teams global meeting policy settings. + + Returns: + dict: Teams global meeting policy settings in JSON format. + + Example: + >>> get_global_meeting_policy() + { + "AllowAnonymousUsersToJoinMeeting": true + } + """ + return self.execute( + "Get-CsTeamsMeetingPolicy -Identity Global | ConvertTo-Json" + ) + def get_user_settings(self) -> dict: """ Get Teams User Settings. diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.metadata.json new file mode 100644 index 0000000000..2cadb55db7 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_anonymous_user_join_disabled", + "CheckTitle": "Ensure anonymous users are not able to join meetings.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure individuals who are not sent or forwarded a meeting invite will not be able to join the meeting automatically.", + "Risk": "Allowing anonymous users to join meetings can lead to unauthorized access, information leakage, and potential disruptions, especially in meetings involving sensitive data.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowAnonymousUsersToJoinMeeting $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting join & lobby set Anonymous users can join a meeting to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable anonymous user access to Microsoft Teams meetings to ensure only invited participants can join. This adds a layer of vetting by requiring organizer approval for anyone not explicitly invited.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.py new file mode 100644 index 0000000000..c3f8df2f64 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled.py @@ -0,0 +1,40 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_anonymous_user_join_disabled(Check): + """Check if anonymous users are not able to join meetings. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for anonymous users are not able to join meetings. + + This method checks if anonymous users are not able to join meetings. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = "Anonymous Teams users can join meetings." + + if not global_meeting_policy.allow_anonymous_users_to_join_meeting: + report.status = "PASS" + report.status_extended = "Anonymous Teams users can not join meetings." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 9d1810e437..81e5797e64 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -10,6 +10,7 @@ class Teams(M365Service): super().__init__(provider) self.powershell.connect_microsoft_teams() self.teams_settings = self._get_teams_client_configuration() + self.global_meeting_policy = self._get_global_meeting_policy() self.user_settings = self._get_user_settings() self.powershell.close() @@ -38,6 +39,23 @@ class Teams(M365Service): ) return teams_settings + def _get_global_meeting_policy(self): + logger.info("M365 - Getting Teams global (org-wide default) meeting policy...") + global_meeting_policy = None + try: + global_meeting_policy = self.powershell.get_global_meeting_policy() + if global_meeting_policy: + global_meeting_policy = GlobalMeetingPolicy( + allow_anonymous_users_to_join_meeting=global_meeting_policy.get( + "AllowAnonymousUsersToJoinMeeting", True + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return global_meeting_policy + def _get_user_settings(self): logger.info("M365 - Getting Teams user settings...") user_settings = None @@ -71,6 +89,10 @@ class TeamsSettings(BaseModel): allow_email_into_channel: bool = True +class GlobalMeetingPolicy(BaseModel): + allow_anonymous_users_to_join_meeting: bool = True + + class UserSettings(BaseModel): allow_external_access: bool = True allow_teams_consumer: bool = True diff --git a/tests/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled_test.py new file mode 100644 index 0000000000..899f7514aa --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_anonymous_user_join_disabled/teams_meeting_anonymous_user_join_disabled_test.py @@ -0,0 +1,117 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_anonymous_user_join_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled import ( + teams_meeting_anonymous_user_join_disabled, + ) + + check = teams_meeting_anonymous_user_join_disabled() + result = check.execute() + assert len(result) == 0 + + def test_anonymous_users_can_join_meetings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled import ( + teams_meeting_anonymous_user_join_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_anonymous_users_to_join_meeting=True + ) + + check = teams_meeting_anonymous_user_join_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended == "Anonymous Teams users can join meetings." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_anonymous_users_cannot_join_meetings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_join_disabled.teams_meeting_anonymous_user_join_disabled import ( + teams_meeting_anonymous_user_join_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_anonymous_users_to_join_meeting=False + ) + + check = teams_meeting_anonymous_user_join_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Anonymous Teams users can not join meetings." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index 41874155d5..a35f7f1a7b 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -4,6 +4,7 @@ from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo from prowler.providers.m365.services.teams.teams_service import ( CloudStorageSettings, + GlobalMeetingPolicy, Teams, TeamsSettings, UserSettings, @@ -23,6 +24,10 @@ def mock_get_teams_client_configuration(_): ) +def mock_get_global_meeting_policy(_): + return GlobalMeetingPolicy(allow_anonymous_users_to_join_meeting=False) + + def mock_get_user_settings(_): return UserSettings( allow_external_access=False, @@ -95,3 +100,23 @@ class Test_Teams_Service: allow_teams_consumer_inbound=False, ) teams_client.powershell.close() + + @patch( + "prowler.providers.m365.services.teams.teams_service.Teams._get_global_meeting_policy", + new=mock_get_global_meeting_policy, + ) + def test_get_global_meeting_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + ): + teams_client = Teams( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert teams_client.global_meeting_policy == GlobalMeetingPolicy( + allow_anonymous_users_to_join_meeting=False + ) + teams_client.powershell.close() From bcfeb97e4aebcabcb6c1368303bdcd4f27b01829 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 23 Apr 2025 14:23:33 +0200 Subject: [PATCH 203/359] feat(m365): add the new provider m365 - UI part (#7591) --- ui/actions/providers/providers.ts | 18 +++ ...oviderBadge.tsx => aws-provider-badge.tsx} | 0 ...iderBadge.tsx => azure-provider-badge.tsx} | 0 ...oviderBadge.tsx => gcp-provider-badge.tsx} | 0 ui/components/icons/providers-badge/index.ts | 9 +- ...oviderBadge.tsx => ks8-provider-badge.tsx} | 0 .../providers-badge/m365-provider-badge.tsx | 126 ++++++++++++++++++ ui/components/providers/provider-info.tsx | 4 +- .../providers/radio-group-provider.tsx | 16 ++- .../workflow/forms/connect-account-form.tsx | 13 +- .../workflow/forms/test-connection-form.tsx | 3 +- .../workflow/forms/via-credentials-form.tsx | 40 +++++- .../workflow/forms/via-credentials/index.ts | 1 + .../via-credentials/m365-credentials-form.tsx | 78 +++++++++++ .../ui/entities/get-provider-logo.tsx | 7 +- ui/types/components.ts | 13 +- ui/types/formSchemas.ts | 22 ++- 17 files changed, 326 insertions(+), 24 deletions(-) rename ui/components/icons/providers-badge/{AWSProviderBadge.tsx => aws-provider-badge.tsx} (100%) rename ui/components/icons/providers-badge/{AzureProviderBadge.tsx => azure-provider-badge.tsx} (100%) rename ui/components/icons/providers-badge/{GCPProviderBadge.tsx => gcp-provider-badge.tsx} (100%) rename ui/components/icons/providers-badge/{KS8ProviderBadge.tsx => ks8-provider-badge.tsx} (100%) create mode 100644 ui/components/icons/providers-badge/m365-provider-badge.tsx create mode 100644 ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 95589eff45..6dbb3a0aee 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -186,6 +186,15 @@ export const addCredentialsProvider = async (formData: FormData) => { client_secret: formData.get("client_secret"), tenant_id: formData.get("tenant_id"), }; + } else if (providerType === "m365") { + // Static credentials configuration for M365 + secret = { + client_id: formData.get("client_id"), + client_secret: formData.get("client_secret"), + tenant_id: formData.get("tenant_id"), + user: formData.get("user"), + encrypted_password: formData.get("encrypted_password"), + }; } else if (providerType === "gcp") { // Static credentials configuration for GCP secret = { @@ -280,6 +289,15 @@ export const updateCredentialsProvider = async ( client_secret: formData.get("client_secret"), tenant_id: formData.get("tenant_id"), }; + } else if (providerType === "m365") { + // Static credentials configuration for M365 + secret = { + client_id: formData.get("client_id"), + client_secret: formData.get("client_secret"), + tenant_id: formData.get("tenant_id"), + user: formData.get("user"), + encrypted_password: formData.get("encrypted_password"), + }; } else if (providerType === "gcp") { // Static credentials configuration for GCP secret = { diff --git a/ui/components/icons/providers-badge/AWSProviderBadge.tsx b/ui/components/icons/providers-badge/aws-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/AWSProviderBadge.tsx rename to ui/components/icons/providers-badge/aws-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/AzureProviderBadge.tsx b/ui/components/icons/providers-badge/azure-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/AzureProviderBadge.tsx rename to ui/components/icons/providers-badge/azure-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/GCPProviderBadge.tsx b/ui/components/icons/providers-badge/gcp-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/GCPProviderBadge.tsx rename to ui/components/icons/providers-badge/gcp-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/index.ts b/ui/components/icons/providers-badge/index.ts index 8aa68424a0..86641d82ad 100644 --- a/ui/components/icons/providers-badge/index.ts +++ b/ui/components/icons/providers-badge/index.ts @@ -1,4 +1,5 @@ -export * from "./AWSProviderBadge"; -export * from "./AzureProviderBadge"; -export * from "./GCPProviderBadge"; -export * from "./KS8ProviderBadge"; +export * from "./aws-provider-badge"; +export * from "./azure-provider-badge"; +export * from "./gcp-provider-badge"; +export * from "./ks8-provider-badge"; +export * from "./m365-provider-badge"; diff --git a/ui/components/icons/providers-badge/KS8ProviderBadge.tsx b/ui/components/icons/providers-badge/ks8-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/KS8ProviderBadge.tsx rename to ui/components/icons/providers-badge/ks8-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/m365-provider-badge.tsx b/ui/components/icons/providers-badge/m365-provider-badge.tsx new file mode 100644 index 0000000000..ed5d077dcf --- /dev/null +++ b/ui/components/icons/providers-badge/m365-provider-badge.tsx @@ -0,0 +1,126 @@ +import * as React from "react"; + +import { IconSvgProps } from "@/types"; + +export const M365ProviderBadge: React.FC = ({ + size, + width, + height, + ...props +}) => ( + +); diff --git a/ui/components/providers/provider-info.tsx b/ui/components/providers/provider-info.tsx index 9eea6cdf74..f65d737f58 100644 --- a/ui/components/providers/provider-info.tsx +++ b/ui/components/providers/provider-info.tsx @@ -1,11 +1,11 @@ import React from "react"; import { ConnectionFalse, ConnectionPending, ConnectionTrue } from "../icons"; -import { getProviderLogo } from "../ui/entities"; +import { getProviderLogo, ProviderType } from "../ui/entities"; interface ProviderInfoProps { connected: boolean | null; - provider: "aws" | "azure" | "gcp" | "kubernetes"; + provider: ProviderType; providerAlias: string; providerUID?: string; } diff --git a/ui/components/providers/radio-group-provider.tsx b/ui/components/providers/radio-group-provider.tsx index e376e69ff4..ec77a148db 100644 --- a/ui/components/providers/radio-group-provider.tsx +++ b/ui/components/providers/radio-group-provider.tsx @@ -7,9 +7,13 @@ import { z } from "zod"; import { addProviderFormSchema } from "@/types"; -import { AWSProviderBadge, AzureProviderBadge } from "../icons/providers-badge"; -import { GCPProviderBadge } from "../icons/providers-badge/GCPProviderBadge"; -import { KS8ProviderBadge } from "../icons/providers-badge/KS8ProviderBadge"; +import { + AWSProviderBadge, + AzureProviderBadge, + GCPProviderBadge, + KS8ProviderBadge, + M365ProviderBadge, +} from "../icons/providers-badge"; import { CustomRadio } from "../ui/custom"; import { FormMessage } from "../ui/form"; @@ -55,6 +59,12 @@ export const RadioGroupProvider: React.FC = ({ Microsoft Azure
    + +
    + + Microsoft 365 +
    +
    diff --git a/ui/components/providers/workflow/forms/connect-account-form.tsx b/ui/components/providers/workflow/forms/connect-account-form.tsx index 597943ae36..ed59d16be0 100644 --- a/ui/components/providers/workflow/forms/connect-account-form.tsx +++ b/ui/components/providers/workflow/forms/connect-account-form.tsx @@ -24,22 +24,27 @@ const getProviderFieldDetails = (providerType?: string) => { case "aws": return { label: "Account ID", - placeholder: "123456...", + placeholder: "e.g. 123456789012", }; case "gcp": return { label: "Project ID", - placeholder: "project_id...", + placeholder: "e.g. my-gcp-project", }; case "azure": return { label: "Subscription ID", - placeholder: "fc94207a-d396-4a14-a7fd-12a...", + placeholder: "e.g. fc94207a-d396-4a14-a7fd-12ab34cd56ef", }; case "kubernetes": return { label: "Kubernetes Context", - placeholder: "context_name....", + placeholder: "e.g. my-cluster-context", + }; + case "m365": + return { + label: "Domain ID", + placeholder: "e.g. your-domain.onmicrosoft.com", }; default: return { diff --git a/ui/components/providers/workflow/forms/test-connection-form.tsx b/ui/components/providers/workflow/forms/test-connection-form.tsx index 84bd803f06..db32c4f3cf 100644 --- a/ui/components/providers/workflow/forms/test-connection-form.tsx +++ b/ui/components/providers/workflow/forms/test-connection-form.tsx @@ -18,6 +18,7 @@ import { getTask } from "@/actions/task/tasks"; import { CheckIcon, RocketIcon } from "@/components/icons"; import { useToast } from "@/components/ui"; import { CustomButton } from "@/components/ui/custom"; +import { ProviderType } from "@/components/ui/entities"; import { Form } from "@/components/ui/form"; import { checkTaskStatus } from "@/lib/helper"; import { ApiError, testConnectionFormSchema } from "@/types"; @@ -41,7 +42,7 @@ export const TestConnectionForm = ({ connected: boolean | null; last_checked_at: string | null; }; - provider: "aws" | "azure" | "gcp" | "kubernetes"; + provider: ProviderType; alias: string; scanner_args: Record; }; diff --git a/ui/components/providers/workflow/forms/via-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials-form.tsx index 7be4a613b4..072d2f3640 100644 --- a/ui/components/providers/workflow/forms/via-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials-form.tsx @@ -19,6 +19,7 @@ import { AzureCredentials, GCPCredentials, KubernetesCredentials, + M365Credentials, } from "@/types"; import { ProviderTitleDocs } from "../provider-title-docs"; @@ -26,6 +27,7 @@ import { AWScredentialsForm } from "./via-credentials/aws-credentials-form"; import { AzureCredentialsForm } from "./via-credentials/azure-credentials-form"; import { GCPcredentialsForm } from "./via-credentials/gcp-credentials-form"; import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form"; +import { M365CredentialsForm } from "./via-credentials/m365-credentials-form"; type CredentialsFormSchema = z.infer< ReturnType @@ -36,7 +38,8 @@ type FormType = CredentialsFormSchema & AWSCredentials & AzureCredentials & GCPCredentials & - KubernetesCredentials; + KubernetesCredentials & + M365Credentials; export const ViaCredentialsForm = ({ searchParams, @@ -76,17 +79,25 @@ export const ViaCredentialsForm = ({ client_secret: "", tenant_id: "", } - : providerType === "gcp" + : providerType === "m365" ? { client_id: "", client_secret: "", - refresh_token: "", + tenant_id: "", + user: "", + encrypted_password: "", } - : providerType === "kubernetes" + : providerType === "gcp" ? { - kubeconfig_content: "", + client_id: "", + client_secret: "", + refresh_token: "", } - : {}), + : providerType === "kubernetes" + ? { + kubeconfig_content: "", + } + : {}), }, }); @@ -135,6 +146,18 @@ export const ViaCredentialsForm = ({ message: errorMessage, }); break; + case "/data/attributes/secret/user": + form.setError("user", { + type: "server", + message: errorMessage, + }); + break; + case "/data/attributes/secret/encrypted_password": + form.setError("encrypted_password", { + type: "server", + message: errorMessage, + }); + break; case "/data/attributes/secret/tenant_id": form.setError("tenant_id", { type: "server", @@ -191,6 +214,11 @@ export const ViaCredentialsForm = ({ control={form.control as unknown as Control} /> )} + {providerType === "m365" && ( + } + /> + )} {providerType === "gcp" && ( } diff --git a/ui/components/providers/workflow/forms/via-credentials/index.ts b/ui/components/providers/workflow/forms/via-credentials/index.ts index d3198a1d0e..88bf5587f0 100644 --- a/ui/components/providers/workflow/forms/via-credentials/index.ts +++ b/ui/components/providers/workflow/forms/via-credentials/index.ts @@ -2,3 +2,4 @@ export * from "./aws-credentials-form"; export * from "./azure-credentials-form"; export * from "./gcp-credentials-form"; export * from "./k8s-credentials-form"; +export * from "./m365-credentials-form"; diff --git a/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx new file mode 100644 index 0000000000..1ba6024ffc --- /dev/null +++ b/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx @@ -0,0 +1,78 @@ +import { Control } from "react-hook-form"; + +import { CustomInput } from "@/components/ui/custom"; +import { M365Credentials } from "@/types"; + +export const M365CredentialsForm = ({ + control, +}: { + control: Control; +}) => { + return ( + <> +
    +
    + Connect via Credentials +
    +
    + Please provide the information for your Microsoft 365 credentials. +
    +
    + + + + + + + ); +}; diff --git a/ui/components/ui/entities/get-provider-logo.tsx b/ui/components/ui/entities/get-provider-logo.tsx index e4bf4d0a62..4bfe7cb419 100644 --- a/ui/components/ui/entities/get-provider-logo.tsx +++ b/ui/components/ui/entities/get-provider-logo.tsx @@ -5,9 +5,10 @@ import { AzureProviderBadge, GCPProviderBadge, KS8ProviderBadge, + M365ProviderBadge, } from "@/components/icons/providers-badge"; -export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes"; +export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes" | "m365"; export const getProviderLogo = (provider: ProviderType) => { switch (provider) { @@ -19,6 +20,8 @@ export const getProviderLogo = (provider: ProviderType) => { return ; case "kubernetes": return ; + case "m365": + return ; default: return null; } @@ -34,6 +37,8 @@ export const getProviderName = (provider: ProviderType): string => { return "Google Cloud Platform"; case "kubernetes": return "Kubernetes"; + case "m365": + return "Microsoft 365"; default: return "Unknown Provider"; } diff --git a/ui/types/components.ts b/ui/types/components.ts index 5b2aa59437..b9a9453690 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -238,6 +238,16 @@ export type AzureCredentials = { providerId: string; }; +export type M365Credentials = { + client_id: string; + client_secret: string; + tenant_id: string; + user: string; + encrypted_password: string; + secretName: string; + providerId: string; +}; + export type GCPCredentials = { client_id: string; client_secret: string; @@ -256,7 +266,8 @@ export type CredentialsFormSchema = | AWSCredentials | AzureCredentials | GCPCredentials - | KubernetesCredentials; + | KubernetesCredentials + | M365Credentials; export interface SearchParamsProps { [key: string]: string | string[] | undefined; diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts index b39a7d92a4..3fc096d03d 100644 --- a/ui/types/formSchemas.ts +++ b/ui/types/formSchemas.ts @@ -63,7 +63,7 @@ export const awsCredentialsTypeSchema = z.object({ export const addProviderFormSchema = z .object({ - providerType: z.enum(["aws", "azure", "gcp", "kubernetes"], { + providerType: z.enum(["aws", "azure", "gcp", "kubernetes", "m365"], { required_error: "Please select a provider type", }), }) @@ -80,6 +80,12 @@ export const addProviderFormSchema = z providerUid: z.string(), awsCredentialsType: z.string().optional(), }), + z.object({ + providerType: z.literal("m365"), + providerAlias: z.string(), + providerUid: z.string(), + awsCredentialsType: z.string().optional(), + }), z.object({ providerType: z.literal("gcp"), providerAlias: z.string(), @@ -128,7 +134,19 @@ export const addCredentialsFormSchema = (providerType: string) => .string() .nonempty("Kubeconfig Content is required"), } - : {}), + : providerType === "m365" + ? { + client_id: z.string().nonempty("Client ID is required"), + client_secret: z + .string() + .nonempty("Client Secret is required"), + tenant_id: z.string().nonempty("Tenant ID is required"), + user: z.string().nonempty("User is required"), + encrypted_password: z + .string() + .nonempty("Encrypted Password is required"), + } + : {}), }); export const addCredentialsRoleFormSchema = (providerType: string) => From ca6df269180f1318506b262a4ae86bcb064d45aa Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 23 Apr 2025 15:13:05 +0200 Subject: [PATCH 204/359] chore: remove deprecated launch scan page from old 4-step workflow (#7592) --- .../(set-up-provider)/launch-scan/page.tsx | 50 ------ .../providers/workflow/forms/index.ts | 1 - .../workflow/forms/launch-scan-form.tsx | 160 ------------------ 3 files changed, 211 deletions(-) delete mode 100644 ui/app/(prowler)/providers/(set-up-provider)/launch-scan/page.tsx delete mode 100644 ui/components/providers/workflow/forms/launch-scan-form.tsx diff --git a/ui/app/(prowler)/providers/(set-up-provider)/launch-scan/page.tsx b/ui/app/(prowler)/providers/(set-up-provider)/launch-scan/page.tsx deleted file mode 100644 index cdfba93dbd..0000000000 --- a/ui/app/(prowler)/providers/(set-up-provider)/launch-scan/page.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { redirect } from "next/navigation"; -import React, { Suspense } from "react"; - -import { getProvider } from "@/actions/providers"; -import { LaunchScanForm } from "@/components/providers/workflow/forms"; -import { SkeletonProviderWorkflow } from "@/components/providers/workflow/skeleton-provider-workflow"; - -interface Props { - searchParams: { type: string; id: string }; -} - -export default async function LaunchScanPage({ searchParams }: Props) { - const providerId = searchParams.id; - - if (!providerId) { - redirect("/providers/connect-account"); - } - - const formData = new FormData(); - formData.append("id", providerId); - - const providerData = await getProvider(formData); - - const isConnected = providerData?.data?.attributes?.connection?.connected; - - if (!isConnected) { - redirect("/providers/connect-account"); - } - - return ( - }> - - - ); -} - -async function SSRLaunchScan({ - searchParams, -}: { - searchParams: { type: string; id: string }; -}) { - const formData = new FormData(); - formData.append("id", searchParams.id); - - const providerData = await getProvider(formData); - - return ( - - ); -} diff --git a/ui/components/providers/workflow/forms/index.ts b/ui/components/providers/workflow/forms/index.ts index d7f0d07134..72e1624f77 100644 --- a/ui/components/providers/workflow/forms/index.ts +++ b/ui/components/providers/workflow/forms/index.ts @@ -1,5 +1,4 @@ export * from "./connect-account-form"; -export * from "./launch-scan-form"; export * from "./radio-group-aws-via-credentials-form"; export * from "./test-connection-form"; export * from "./update-via-credentials-form"; diff --git a/ui/components/providers/workflow/forms/launch-scan-form.tsx b/ui/components/providers/workflow/forms/launch-scan-form.tsx deleted file mode 100644 index 968fb8ffb9..0000000000 --- a/ui/components/providers/workflow/forms/launch-scan-form.tsx +++ /dev/null @@ -1,160 +0,0 @@ -"use client"; - -import { zodResolver } from "@hookform/resolvers/zod"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; - -import { scanOnDemand } from "@/actions/scans/scans"; -import { AddIcon } from "@/components/icons"; -import { CustomButton } from "@/components/ui/custom"; -import { Form } from "@/components/ui/form"; -import { ProviderProps } from "@/types"; // Asegúrate de importar la interfaz correcta -import { launchScanFormSchema } from "@/types/formSchemas"; - -import { ProviderInfo } from "../../provider-info"; - -type FormValues = z.infer>; - -interface LaunchScanFormProps { - searchParams: { type: string; id: string }; - providerData: { - data: { - type: string; - id: string; - attributes: ProviderProps["attributes"]; - }; - }; -} - -export const LaunchScanForm = ({ - searchParams, - providerData, -}: LaunchScanFormProps) => { - const providerType = searchParams.type; - const providerId = searchParams.id; - - const [apiErrorMessage, setApiErrorMessage] = useState(null); - const router = useRouter(); - - const formSchema = launchScanFormSchema(); - - const form = useForm({ - resolver: zodResolver(formSchema), - defaultValues: { - providerId, - providerType, - scannerArgs: { - checksToExecute: [], - }, - }, - }); - - // const isLoading = form.formState.isSubmitting; - - const onSubmitClient = async (values: FormValues) => { - const formData = new FormData(); - formData.append("providerId", values.providerId); - - // Generate default scan name using provider type and current date - const date = new Date(); - const month = (date.getMonth() + 1).toString().padStart(2, "0"); - const day = date.getDate().toString().padStart(2, "0"); - const year = date.getFullYear(); - const defaultScanName = `${providerType}:${month}/${day}/${year}`; - - formData.append("scanName", defaultScanName); - - try { - const data = await scanOnDemand(formData); - - if (data.error) { - setApiErrorMessage(data.error); - form.setError("providerId", { - type: "server", - message: data.error, - }); - } else { - router.push("/scans"); - } - } catch (error) { - form.setError("providerId", { - type: "server", - message: "An unexpected error occurred. Please try again.", - }); - } - }; - - return ( -
    - -
    -
    Scan started
    -
    - The scan has just started. From now on, a new scan will be launched - every 24 hours, starting from this moment. -
    -
    - - {apiErrorMessage && ( -
    -

    {apiErrorMessage.toLowerCase()}

    -
    - )} - - - - - - - {/*
    - } - isDisabled={true} - > - Schedule - - } - > - {isLoading ? <>Loading : Start now} - -
    */} -
    - } - > - Go to Scans - -
    - - - ); -}; From 190fd0b93c2d4a8210b088cb8b855bd4f2cd5236 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 23 Apr 2025 08:58:04 -0500 Subject: [PATCH 205/359] fix(scan): handle cloud provider errors and ignore expected sentry noise (#7582) --- api/src/backend/config/settings/sentry.py | 5 +++-- .../cloudtrail_multi_region_enabled.py | 5 +++++ .../providers/aws/services/iam/iam_service.py | 11 ++++++++--- .../services/defender/defender_service.py | 2 +- .../gcp/services/cloudsql/cloudsql_service.py | 18 +++++++++--------- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py index 5aeda7a88a..bf354b90e5 100644 --- a/api/src/backend/config/settings/sentry.py +++ b/api/src/backend/config/settings/sentry.py @@ -39,6 +39,9 @@ IGNORED_EXCEPTIONS = [ "RequestExpired", "ConnectionClosedError", "MaxRetryError", + "AWSAccessKeyIDInvalidError", + "AWSSessionTokenExpiredError", + "EndpointConnectionError", # AWS Service is not available in a region "Pool is closed", # The following comes from urllib3: eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed. # Authentication Errors from GCP "ClientAuthenticationError", @@ -63,8 +66,6 @@ IGNORED_EXCEPTIONS = [ "AzureClientIdAndClientSecretNotBelongingToTenantIdError", "AzureHTTPResponseError", "Error with credentials provided", - # AWS Service is not available in a region - "EndpointConnectionError", ] diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py index b4b7349fc4..16bb264e28 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled/cloudtrail_multi_region_enabled.py @@ -29,10 +29,15 @@ class cloudtrail_multi_region_enabled(Check): break # If there are no trails logging it is needed to store the FAIL once all the trails have been checked if not trail_is_logging: + report = Check_Report_AWS( + metadata=self.metadata(), + resource={}, + ) report.status = "FAIL" report.status_extended = ( "No CloudTrail trails enabled with logging were found." ) + report.region = region report.resource_arn = cloudtrail_client._get_trail_arn_template( region ) diff --git a/prowler/providers/aws/services/iam/iam_service.py b/prowler/providers/aws/services/iam/iam_service.py index 2601377cfe..dafd86017c 100644 --- a/prowler/providers/aws/services/iam/iam_service.py +++ b/prowler/providers/aws/services/iam/iam_service.py @@ -880,9 +880,14 @@ class IAM(AWSService): SAMLProviderArn=resource.arn ).get("Tags", []) except Exception as error: - logger.error( - f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + if error.response["Error"]["Code"] == "NoSuchEntityException": + logger.warning( + f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + else: + logger.error( + f"{self.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) def _get_last_accessed_services(self): logger.info("IAM - Getting Last Accessed Services ...") diff --git a/prowler/providers/azure/services/defender/defender_service.py b/prowler/providers/azure/services/defender/defender_service.py index f308a838bd..6b66eaa1c8 100644 --- a/prowler/providers/azure/services/defender/defender_service.py +++ b/prowler/providers/azure/services/defender/defender_service.py @@ -161,7 +161,7 @@ class Defender(AzureService): { security_contact_default.name: SecurityContacts( resource_id=security_contact_default.id, - name=security_contact_default.get("name", "default"), + name=getattr(security_contact_default, "name", "default"), emails=security_contact_default.emails, phone=security_contact_default.phone, alert_notifications_minimal_severity=security_contact_default.alert_notifications.minimal_severity, diff --git a/prowler/providers/gcp/services/cloudsql/cloudsql_service.py b/prowler/providers/gcp/services/cloudsql/cloudsql_service.py index 539671173b..d0dbe5137d 100644 --- a/prowler/providers/gcp/services/cloudsql/cloudsql_service.py +++ b/prowler/providers/gcp/services/cloudsql/cloudsql_service.py @@ -30,18 +30,18 @@ class CloudSQL(GCPService): region=instance["region"], ip_addresses=instance.get("ipAddresses", []), public_ip=public_ip, - require_ssl=instance["settings"]["ipConfiguration"].get( - "requireSsl", False - ), - ssl_mode=instance["settings"]["ipConfiguration"].get( - "sslMode", "ALLOW_UNENCRYPTED_AND_ENCRYPTED" - ), + require_ssl=instance["settings"] + .get("ipConfiguration", {}) + .get("requireSsl", False), + ssl_mode=instance["settings"] + .get("ipConfiguration", {}) + .get("sslMode", "ALLOW_UNENCRYPTED_AND_ENCRYPTED"), automated_backups=instance["settings"][ "backupConfiguration" ]["enabled"], - authorized_networks=instance["settings"][ - "ipConfiguration" - ]["authorizedNetworks"], + authorized_networks=instance["settings"] + .get("ipConfiguration", {}) + .get("authorizedNetworks", []), flags=instance["settings"].get("databaseFlags", []), project_id=project_id, ) From 738ce569558e79ea7360e42be7b60fddd97adf78 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:58:32 +0200 Subject: [PATCH 206/359] fix(docs): overview m365 auth (#7588) --- docs/getting-started/requirements.md | 9 ++++++++- docs/index.md | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index 6e4ba9c267..81791b1b31 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -134,6 +134,8 @@ Prowler for M365 currently supports the following authentication types: ### Service Principal authentication +Authentication flag: `--sp-env-auth` + To allow Prowler assume the service principal identity to start the scan it is needed to configure the following environment variables: ```console @@ -146,6 +148,9 @@ If you try to execute Prowler with the `--sp-env-auth` flag and those variables Follow the instructions in the [Create Prowler Service Principal](../tutorials/azure/create-prowler-service-principal.md) section to create a service principal. ### Service Principal and User Credentials authentication (recommended) + +Authentication flag: `--env-auth` + This authentication method follows the same approach as the service principal method but introduces two additional environment variables for user credentials: `M365_USER` and `M365_ENCRYPTED_PASSWORD`. ```console @@ -176,4 +181,6 @@ Write-Output $encryptedPassword ### Interactive Browser authentication -To use `--browser-auth` the user needs to authenticate against Azure using the default browser to start the scan, also `--tenant-id` flag is required. +Authentication flag: `--browser-auth` + +This authentication method requires the user to authenticate against Azure using the default browser to start the scan, also `--tenant-id` flag is required. diff --git a/docs/index.md b/docs/index.md index ac8d50461f..ff63c9fd02 100644 --- a/docs/index.md +++ b/docs/index.md @@ -570,6 +570,10 @@ kubectl logs prowler-XXXXX --namespace prowler-ns With M365 you need to specify which auth method is going to be used: ```console + +# To use both service principal (for MSGraph) and user credentials (for PowerShell modules) +prowler m365 --env-auth + # To use service principal authentication prowler m365 --sp-env-auth From 808e8297b053bdc91fc657385e9fc558276502a2 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:31:17 +0200 Subject: [PATCH 207/359] feat(teams): add new check `teams_meeting_anonymous_user_start_disabled` (#7567) --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...nonymous_user_start_disabled.metadata.json | 30 +++++ ...s_meeting_anonymous_user_start_disabled.py | 40 ++++++ .../m365/services/teams/teams_service.py | 6 +- ...ting_anonymous_user_start_disabled_test.py | 117 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 8 +- 7 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 6c8ffb5b0d..a938b5cf3e 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) +- Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.metadata.json new file mode 100644 index 0000000000..b8de5d3fb0 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_anonymous_user_start_disabled", + "CheckTitle": "Ensure anonymous users are not able to start meetings.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure anonymous users and dial-in callers are not able to start meetings.", + "Risk": "Allowing anonymous users and dial-in callers to start meetings without an authenticated participant present can lead to meeting spamming, unauthorized activity, and potential misuse of organizational resources.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowAnonymousUsersToStartMeeting $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting join & lobby set Anonymous users and dial-in callers can start a meeting to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that anonymous users and dial-in callers are required to wait in the lobby until a verified user from the organization or a trusted external domain starts the meeting. This reduces the risk of abuse and maintains meeting integrity.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.py new file mode 100644 index 0000000000..cae9198a54 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled.py @@ -0,0 +1,40 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_anonymous_user_start_disabled(Check): + """Check if anonymous users are not able to start meetings. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for anonymous users are not able to start meetings. + + This method checks if anonymous users and dial-in callers are not able to start meetings. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = "Anonymous Teams users can start meetings." + + if not global_meeting_policy.allow_anonymous_users_to_start_meeting: + report.status = "PASS" + report.status_extended = "Anonymous Teams users can not start meetings." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 81e5797e64..7231176b9a 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -48,7 +48,10 @@ class Teams(M365Service): global_meeting_policy = GlobalMeetingPolicy( allow_anonymous_users_to_join_meeting=global_meeting_policy.get( "AllowAnonymousUsersToJoinMeeting", True - ) + ), + allow_anonymous_users_to_start_meeting=global_meeting_policy.get( + "AllowAnonymousUsersToStartMeeting", True + ), ) except Exception as error: logger.error( @@ -91,6 +94,7 @@ class TeamsSettings(BaseModel): class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_join_meeting: bool = True + allow_anonymous_users_to_start_meeting: bool = True class UserSettings(BaseModel): diff --git a/tests/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled_test.py new file mode 100644 index 0000000000..6eda43d319 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_anonymous_user_start_disabled/teams_meeting_anonymous_user_start_disabled_test.py @@ -0,0 +1,117 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_anonymous_user_start_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled import ( + teams_meeting_anonymous_user_start_disabled, + ) + + check = teams_meeting_anonymous_user_start_disabled() + result = check.execute() + assert len(result) == 0 + + def test_anonymous_users_can_start_meetings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled import ( + teams_meeting_anonymous_user_start_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_anonymous_users_to_start_meeting=True + ) + + check = teams_meeting_anonymous_user_start_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended == "Anonymous Teams users can start meetings." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_anonymous_users_cannot_start_meetings(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_anonymous_user_start_disabled.teams_meeting_anonymous_user_start_disabled import ( + teams_meeting_anonymous_user_start_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_anonymous_users_to_start_meeting=False + ) + + check = teams_meeting_anonymous_user_start_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Anonymous Teams users can not start meetings." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index a35f7f1a7b..a4b523eaf7 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -25,7 +25,10 @@ def mock_get_teams_client_configuration(_): def mock_get_global_meeting_policy(_): - return GlobalMeetingPolicy(allow_anonymous_users_to_join_meeting=False) + return GlobalMeetingPolicy( + allow_anonymous_users_to_join_meeting=False, + allow_anonymous_users_to_start_meeting=False, + ) def mock_get_user_settings(_): @@ -117,6 +120,7 @@ class Test_Teams_Service: ) ) assert teams_client.global_meeting_policy == GlobalMeetingPolicy( - allow_anonymous_users_to_join_meeting=False + allow_anonymous_users_to_join_meeting=False, + allow_anonymous_users_to_start_meeting=False, ) teams_client.powershell.close() From deb1e0ff3433a9cf2dab4e4857da598e2e410a63 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:29:24 +0200 Subject: [PATCH 208/359] feat(defender): Add new check `defender_antispam_policy_inbound_no_allowed_domains` (#7500) Co-authored-by: HugoPBrito Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 18 +++ .../__init__.py | 0 ...y_inbound_no_allowed_domains.metadata.json | 30 +++++ ...ispam_policy_inbound_no_allowed_domains.py | 42 ++++++ .../services/defender/defender_service.py | 31 +++++ ..._policy_inbound_no_allowed_domains_test.py | 126 ++++++++++++++++++ .../defender/m365_defender_service_test.py | 34 +++++ 8 files changed, 282 insertions(+) create mode 100644 prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/__init__.py create mode 100644 prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.metadata.json create mode 100644 prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py create mode 100644 tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index a938b5cf3e..9d77a9198b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add check for Inbound Antispam Policy with no allowed domains from service Defender in M365 [(#7500)](https://github.com/prowler-cloud/prowler/pull/7500) - Add new check `teams_meeting_anonymous_user_join_disabled` [(#7565)](https://github.com/prowler-cloud/prowler/pull/7565) - Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561) - Add new check `teams_external_users_cannot_start_conversations` [(#7562)](https://github.com/prowler-cloud/prowler/pull/7562) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 7b272cc748..bca020cf9c 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -379,3 +379,21 @@ class M365PowerShell(PowerShellSession): } """ return self.execute("Get-DkimSigningConfig | ConvertTo-Json") + + def get_inbound_spam_filter_policy(self) -> dict: + """ + Get Inbound Spam Filter Policy. + + Retrieves the current inbound spam filter policy settings for Exchange Online. + + Returns: + dict: Inbound spam filter policy settings in JSON format. + + Example: + >>> get_inbound_spam_filter_policy() + { + "Identity": "Default", + "AllowedSenderDomains": "[]" + } + """ + return self.execute("Get-HostedContentFilterPolicy | ConvertTo-Json") diff --git a/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/__init__.py b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.metadata.json b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.metadata.json new file mode 100644 index 0000000000..2d4537c400 --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "defender_antispam_policy_inbound_no_allowed_domains", + "CheckTitle": "Ensure inbound anti-spam policies do not contain allowed domains", + "CheckType": [], + "ServiceName": "defender", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "low", + "ResourceType": "Defender Anti-Spam Policy", + "Description": "Ensure that inbound anti-spam policies do not have any domains listed in the AllowedSenderDomains. Messages from these domains bypass most email protections, increasing the risk of successful phishing attacks.", + "Risk": "Having domains in the AllowedSenderDomains list allows emails from these domains to bypass essential security checks, increasing the risk of phishing attacks and other malicious activities.", + "RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/anti-spam-protection-about#allow-and-block-lists-in-anti-spam-policies", + "Remediation": { + "Code": { + "CLI": "Set-HostedContentFilterPolicy -Identity -AllowedSenderDomains @{}", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 Defender (https://security.microsoft.com). 2. Click to expand Email & collaboration and select Policies & rules > Threat policies. 3. Under Policies, select Anti-spam. 4. Open each out-of-compliance inbound anti-spam policy by clicking on it. 5. Click Edit allowed and blocked senders and domains. 6. Select Allow domains. 7. Delete each domain from the domains list. 8. Click Done > Save. 9. Repeat as needed.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that the AllowedSenderDomains list in your inbound anti-spam policies is empty to prevent bypassing essential security checks.", + "Url": "https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/configure-the-allowed-sender-domains?view=o365-worldwide" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py new file mode 100644 index 0000000000..71dbb7e45f --- /dev/null +++ b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.defender.defender_client import defender_client + + +class defender_antispam_policy_inbound_no_allowed_domains(Check): + """ + Check if the inbound anti-spam policies do not contain allowed domains in Microsoft 365 Defender. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to verify if inbound anti-spam policies do not contain allowed domains. + + This method checks each inbound anti-spam policy to determine if the AllowedSenderDomains + list is empty or undefined. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + for policy in defender_client.inbound_spam_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name="Defender Inbound Spam Policy", + resource_id=policy.identity, + ) + report.status = "PASS" + report.status_extended = f"Inbound anti-spam policy {policy.identity} does not contain allowed domains." + + if policy.allowed_sender_domains: + report.status = "FAIL" + report.status_extended = f"Inbound anti-spam policy {policy.identity} contains allowed domains: {policy.allowed_sender_domains}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 51f53a0606..4fc86aa51c 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -16,6 +16,7 @@ class Defender(M365Service): self.outbound_spam_rules = self._get_outbound_spam_filter_rule() self.antiphishing_policies = self._get_antiphising_policy() self.antiphising_rules = self._get_antiphising_rules() + self.inbound_spam_policies = self._get_inbound_spam_filter_policy() self.connection_filter_policy = self._get_connection_filter_policy() self.dkim_configurations = self._get_dkim_config() self.powershell.close() @@ -179,6 +180,31 @@ class Defender(M365Service): ) return outbound_spam_rules + def _get_inbound_spam_filter_policy(self): + logger.info("Microsoft365 - Getting Defender inbound spam filter policy...") + inbound_spam_policies = [] + try: + inbound_spam_policy = self.powershell.get_inbound_spam_filter_policy() + if not inbound_spam_policy: + return inbound_spam_policies + if isinstance(inbound_spam_policy, dict): + inbound_spam_policy = [inbound_spam_policy] + for policy in inbound_spam_policy: + if policy: + inbound_spam_policies.append( + DefenderInboundSpamPolicy( + identity=policy.get("Identity", ""), + allowed_sender_domains=policy.get( + "AllowedSenderDomains", [] + ), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return inbound_spam_policies + class MalwarePolicy(BaseModel): enable_file_filter: bool @@ -224,3 +250,8 @@ class OutboundSpamPolicy(BaseModel): class OutboundSpamRule(BaseModel): state: str + + +class DefenderInboundSpamPolicy(BaseModel): + identity: str + allowed_sender_domains: list[str] = [] diff --git a/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py b/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py new file mode 100644 index 0000000000..feba0c5bb4 --- /dev/null +++ b/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py @@ -0,0 +1,126 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_defender_antispam_policy_inbound_no_allowed_domains: + def test_policy_without_allowed_domains(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Policy1", + allowed_sender_domains=[], + ) + ] + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Inbound anti-spam policy Policy1 does not contain allowed domains." + ) + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + assert result[0].resource_name == "Defender Inbound Spam Policy" + assert result[0].resource_id == "Policy1" + assert result[0].location == "global" + + def test_policy_with_allowed_domains(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Policy2", + allowed_sender_domains=["bad-domain.com"], + ) + ] + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Inbound anti-spam policy Policy2 contains allowed domains: ['bad-domain.com']." + ) + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + assert result[0].resource_name == "Defender Inbound Spam Policy" + assert result[0].resource_id == "Policy2" + assert result[0].location == "global" + + def test_no_inbound_spam_policies(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + + defender_client.inbound_spam_policies = [] + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 28d9d47919..efce49f843 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -7,6 +7,7 @@ from prowler.providers.m365.services.defender.defender_service import ( AntiphishingRule, ConnectionFilterPolicy, Defender, + DefenderInboundSpamPolicy, DkimConfig, MalwarePolicy, OutboundSpamPolicy, @@ -70,6 +71,19 @@ def mock_defender_get_antiphising_rules(_): } +def mock_defender_get_inbound_spam_policy(_): + return [ + DefenderInboundSpamPolicy( + identity="Policy1", + allowed_sender_domains=[], + ), + DefenderInboundSpamPolicy( + identity="Policy2", + allowed_sender_domains=["example.com"], + ), + ] + + def mock_defender_get_connection_filter_policy(_): return ConnectionFilterPolicy( ip_allow_list=[], @@ -323,3 +337,23 @@ class Test_Defender_Service: outbound_spam_rules = defender_client.outbound_spam_rules assert outbound_spam_rules["Policy1"].state == "Enabled" assert outbound_spam_rules["Policy2"].state == "Disabled" + + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_inbound_spam_filter_policy", + new=mock_defender_get_inbound_spam_policy, + ) + def test__get_inbound_spam_filter_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + inbound_spam_policies = defender_client.inbound_spam_policies + assert inbound_spam_policies[0].allowed_sender_domains == [] + assert inbound_spam_policies[1].allowed_sender_domains == ["example.com"] + defender_client.powershell.close() From 12c24391962f3df5daa8583bd3ee1c3853af1a34 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:47:51 +0200 Subject: [PATCH 209/359] feat(exchange): add new check `exchange_transport_rules_whitelist_disabled` (#7569) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 19 +++ .../services/exchange/exchange_service.py | 33 +++++ .../__init__.py | 0 ...ort_rules_whitelist_disabled.metadata.json | 30 ++++ ...ange_transport_rules_whitelist_disabled.py | 47 ++++++ .../exchange/exchange_service_test.py | 42 ++++++ ...transport_rules_whitelist_disabled_test.py | 135 ++++++++++++++++++ 8 files changed, 307 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9d77a9198b..ef4f2da150 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check for WhiteList not used in Transport Rules for service Defender in M365 [(#7569)](https://github.com/prowler-cloud/prowler/pull/7569) - Add check for Inbound Antispam Policy with no allowed domains from service Defender in M365 [(#7500)](https://github.com/prowler-cloud/prowler/pull/7500) - Add new check `teams_meeting_anonymous_user_join_disabled` [(#7565)](https://github.com/prowler-cloud/prowler/pull/7565) - Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index bca020cf9c..7a47a2025f 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -342,6 +342,25 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") + def get_transport_rules(self) -> dict: + """ + Get Exchange Online Transport Rules. + + Retrieves the current transport rules configured in Exchange Online. + + Returns: + dict: Transport rules in JSON format. + + Example: + >>> get_transport_rules() + { + "Name": "Rule1", + "SetSCL": -1, + "SenderDomainIs": ["example.com"] + } + """ + return self.execute("Get-TransportRule | ConvertTo-Json") + def get_connection_filter_policy(self) -> dict: """ Get Exchange Online Connection Filter Policy. diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index f369edb6b5..9fd547f7b7 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import BaseModel from prowler.lib.logger import logger @@ -11,6 +13,7 @@ class Exchange(M365Service): self.powershell.connect_exchange_online() self.organization_config = self._get_organization_config() self.mailboxes_config = self._get_mailbox_audit_config() + self.transport_rules = self._get_transport_rules() self.powershell.close() def _get_organization_config(self): @@ -53,6 +56,30 @@ class Exchange(M365Service): ) return mailboxes_config + def _get_transport_rules(self): + logger.info("Microsoft365 - Getting transport rules configuration...") + transport_rules = [] + try: + rules_data = self.powershell.get_transport_rules() + if not rules_data: + return transport_rules + if isinstance(rules_data, dict): + rules_data = [rules_data] + for rule in rules_data: + if rule: + transport_rules.append( + TransportRule( + name=rule.get("Name", ""), + scl=rule.get("SetSCL", None), + sender_domain_is=rule.get("SenderDomainIs", []), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return transport_rules + class Organization(BaseModel): name: str @@ -64,3 +91,9 @@ class MailboxAuditConfig(BaseModel): name: str id: str audit_bypass_enabled: bool + + +class TransportRule(BaseModel): + name: str + scl: Optional[int] + sender_domain_is: list[str] diff --git a/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.metadata.json new file mode 100644 index 0000000000..d762b3be0e --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_transport_rules_whitelist_disabled", + "CheckTitle": "Ensure mail transport rules do not whitelist specific domains", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Transport Rules", + "Description": "Mail flow rules (transport rules) in Exchange Online are used to identify and take action on messages that flow through the organization.", + "Risk": "Whitelisting domains in transport rules bypasses regular malware and phishing scanning, which can enable an attacker to launch attacks against your users from a safe haven domain.", + "RelatedUrl": "https://learn.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/configuration-best-practices", + "Remediation": { + "Code": { + "CLI": "Remove-TransportRule -Identity ", + "NativeIaC": "", + "Other": "1. Navigate to Exchange admin center https://admin.exchange.microsoft.com.. 2. Click to expand Mail Flow and then select Rules. 3. For each rule that whitelists specific domains, select the rule and click the 'Delete' icon.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Remove transport rules that whitelist specific domains to ensure proper scanning.", + "Url": "https://learn.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/mail-flow-rules" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py new file mode 100644 index 0000000000..ec74c9ff75 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py @@ -0,0 +1,47 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_transport_rules_whitelist_disabled(Check): + """ + Check to ensure that no mail transport rules whitelist specific domains. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to validate that no transport rules whitelist specific domains. + + This method retrieves all transport rules from the Exchange service and evaluates + whether any of them whitelist specific domains. A report is generated for each + transport rule. + + Returns: + List[CheckReportM365]: A list of findings with the status of each transport rule. + """ + findings = [] + + for rule in exchange_client.transport_rules: + report = CheckReportM365( + metadata=self.metadata(), + resource=rule, + resource_name=rule.name, + resource_id="ExchangeTransportRule", + ) + + report.status = "PASS" + report.status_extended = ( + f"Transport rule '{rule.name}' does not whitelist any domains." + ) + + if rule.sender_domain_is and rule.scl == -1: + report.status = "FAIL" + report.status_extended = f"Transport rule '{rule.name}' whitelists domains: {', '.join(rule.sender_domain_is)}." + + findings.append(report) + + return findings diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 83e1af83a5..1d74474e3d 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, MailboxAuditConfig, Organization, + TransportRule, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -21,6 +22,21 @@ def mock_exchange_get_mailbox_audit_config(_): ] +def mock_exchange_get_transport_rules(_): + return [ + TransportRule( + name="test", + scl=-1, + sender_domain_is=["example.com"], + ), + TransportRule( + name="test2", + scl=0, + sender_domain_is=["example.com"], + ), + ] + + class Test_Exchange_Service: def test_get_client(self): with ( @@ -84,3 +100,29 @@ class Test_Exchange_Service: assert mailbox_audit_config[1].audit_bypass_enabled is True exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_transport_rules", + new=mock_exchange_get_transport_rules, + ) + def test_get_transport_rules(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + transport_rules = exchange_client.transport_rules + assert len(transport_rules) == 2 + assert transport_rules[0].name == "test" + assert transport_rules[0].scl == -1 + assert transport_rules[0].sender_domain_is == ["example.com"] + assert transport_rules[1].name == "test2" + assert transport_rules[1].scl == 0 + assert transport_rules[1].sender_domain_is == ["example.com"] + + exchange_client.powershell.close() diff --git a/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py b/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py new file mode 100644 index 0000000000..ad51a64b58 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py @@ -0,0 +1,135 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_transport_rules_whitelist_disabled: + def test_no_whitelist_domains(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_service import ( + TransportRule, + ) + from prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled import ( + exchange_transport_rules_whitelist_disabled, + ) + + exchange_client.transport_rules = [ + TransportRule(name="Rule1", scl=0, sender_domain_is=[]), + TransportRule(name="Rule2", scl=0, sender_domain_is=["example.com"]), + ] + + check = exchange_transport_rules_whitelist_disabled() + result = check.execute() + + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Transport rule 'Rule1' does not whitelist any domains." + ) + assert result[0].resource_name == "Rule1" + assert result[0].resource_id == "ExchangeTransportRule" + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Transport rule 'Rule2' does not whitelist any domains." + ) + assert result[1].resource_name == "Rule2" + + def test_whitelist_detected(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_service import ( + TransportRule, + ) + from prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled import ( + exchange_transport_rules_whitelist_disabled, + ) + + exchange_client.transport_rules = [ + TransportRule( + name="WhitelistRule", scl=-1, sender_domain_is=["whitelist.com"] + ), + TransportRule(name="NoWhitelistRule", scl=-1, sender_domain_is=[]), + ] + + check = exchange_transport_rules_whitelist_disabled() + result = check.execute() + + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Transport rule 'WhitelistRule' whitelists domains: whitelist.com." + ) + assert result[0].resource_name == "WhitelistRule" + assert result[0].resource_id == "ExchangeTransportRule" + assert result[0].location == "global" + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Transport rule 'NoWhitelistRule' does not whitelist any domains." + ) + assert result[1].resource_name == "NoWhitelistRule" + assert result[1].resource_id == "ExchangeTransportRule" + assert result[1].location == "global" + + def test_empty_rule_list(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_transport_rules_whitelist_disabled.exchange_transport_rules_whitelist_disabled import ( + exchange_transport_rules_whitelist_disabled, + ) + + exchange_client.transport_rules = [] + + check = exchange_transport_rules_whitelist_disabled() + result = check.execute() + + assert len(result) == 0 From 8e3c856a147d316333fa611c9d287af5fb199cdd Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 23 Apr 2025 20:11:39 +0200 Subject: [PATCH 210/359] feat(exchange): add new check `exchange_external_email_tagging_enabled` (#7580) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 18 ++ .../__init__.py | 0 ...ternal_email_tagging_enabled.metadata.json | 30 +++ ...exchange_external_email_tagging_enabled.py | 41 +++++ .../services/exchange/exchange_service.py | 31 ++++ ...ange_transport_rules_whitelist_disabled.py | 4 +- ...nge_external_email_tagging_enabled_test.py | 173 ++++++++++++++++++ .../exchange/exchange_service_test.py | 37 ++++ ...transport_rules_whitelist_disabled_test.py | 8 +- 10 files changed, 337 insertions(+), 6 deletions(-) create mode 100644 prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index ef4f2da150..1bb4df58ab 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418) - Add new check `teams_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557) - Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533) +- Add new check for External Mails Tagged for service Exchange in M365 [(#7580)](https://github.com/prowler-cloud/prowler/pull/7580) - Add new check for WhiteList not used in Transport Rules for service Defender in M365 [(#7569)](https://github.com/prowler-cloud/prowler/pull/7569) - Add check for Inbound Antispam Policy with no allowed domains from service Defender in M365 [(#7500)](https://github.com/prowler-cloud/prowler/pull/7500) - Add new check `teams_meeting_anonymous_user_join_disabled` [(#7565)](https://github.com/prowler-cloud/prowler/pull/7565) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 7a47a2025f..8e4df5b94d 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -342,6 +342,24 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") + def get_external_mail_config(self) -> dict: + """ + Get Exchange Online External Mail Configuration. + + Retrieves the current external mail configuration settings for Exchange Online. + + Returns: + dict: External mail configuration settings in JSON format. + + Example: + >>> get_external_mail_config() + { + "Identity": "MyExternalMail", + "ExternalMailTagEnabled": true + } + """ + return self.execute("Get-ExternalInOutlook | ConvertTo-Json") + def get_transport_rules(self) -> dict: """ Get Exchange Online Transport Rules. diff --git a/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.metadata.json new file mode 100644 index 0000000000..a1ddac7890 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_external_email_tagging_enabled", + "CheckTitle": "Ensure email from external senders is identified.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Exchange External Mail Tagging", + "Description": "Ensure that emails from external senders are identified using the native External tag experience in Outlook clients, which helps users recognize messages originating outside the organization.", + "Risk": "If external email tagging is not enabled, users may be unable to quickly identify emails coming from outside the organization, increasing the risk of phishing or social engineering attacks.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-externalinoutlook?view=exchange-ps", + "Remediation": { + "Code": { + "CLI": "Set-ExternalInOutlook -Enabled $true", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable the External tag for Outlook to help users visually identify emails from outside the organization.", + "Url": "https://techcommunity.microsoft.com/t5/exchange-team-blog/native-external-sender-callouts-on-email-in-outlook/ba-p/2250098" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.py b/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.py new file mode 100644 index 0000000000..5d2c3eeb81 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled.py @@ -0,0 +1,41 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_external_email_tagging_enabled(Check): + """Ensure email from external senders is identified. + + This check verifies that the native "External" sender tag feature is enabled + in Exchange so that messages from outside the organization are automatically marked. + """ + + def execute(self) -> List[CheckReportM365]: + """Run the check to validate that external sender tagging is enabled. + + Iterates through the external mail configuration to determine if the + ExternalInOutlook setting is turned on and generates a report accordingly. + + Returns: + List[CheckReportM365]: A list of reports for each organization identity. + """ + findings = [] + + for mail_config in exchange_client.external_mail_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=mail_config, + resource_name=mail_config.identity, + resource_id=mail_config.identity, + ) + report.status = "FAIL" + report.status_extended = f"External sender tagging is disabled for Exchange identity {mail_config.identity}." + + if mail_config.external_mail_tag_enabled: + report.status = "PASS" + report.status_extended = f"External sender tagging is enabled for Exchange identity {mail_config.identity}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 9fd547f7b7..c1d544787f 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -13,6 +13,7 @@ class Exchange(M365Service): self.powershell.connect_exchange_online() self.organization_config = self._get_organization_config() self.mailboxes_config = self._get_mailbox_audit_config() + self.external_mail_config = self._get_external_mail_config() self.transport_rules = self._get_transport_rules() self.powershell.close() @@ -56,6 +57,31 @@ class Exchange(M365Service): ) return mailboxes_config + def _get_external_mail_config(self): + logger.info("Microsoft365 - Getting external mail configuration...") + external_mail_config = [] + try: + external_mail_configuration = self.powershell.get_external_mail_config() + if not external_mail_configuration: + return external_mail_config + if isinstance(external_mail_configuration, dict): + external_mail_configuration = [external_mail_configuration] + for external_mail in external_mail_configuration: + if external_mail: + external_mail_config.append( + ExternalMailConfig( + identity=external_mail.get("Identity", ""), + external_mail_tag_enabled=external_mail.get( + "Enabled", False + ), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return external_mail_config + def _get_transport_rules(self): logger.info("Microsoft365 - Getting transport rules configuration...") transport_rules = [] @@ -93,6 +119,11 @@ class MailboxAuditConfig(BaseModel): audit_bypass_enabled: bool +class ExternalMailConfig(BaseModel): + identity: str + external_mail_tag_enabled: bool + + class TransportRule(BaseModel): name: str scl: Optional[int] diff --git a/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py index ec74c9ff75..58cd7b23bc 100644 --- a/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py +++ b/prowler/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled.py @@ -35,12 +35,12 @@ class exchange_transport_rules_whitelist_disabled(Check): report.status = "PASS" report.status_extended = ( - f"Transport rule '{rule.name}' does not whitelist any domains." + f"Transport rule {rule.name} does not whitelist any domains." ) if rule.sender_domain_is and rule.scl == -1: report.status = "FAIL" - report.status_extended = f"Transport rule '{rule.name}' whitelists domains: {', '.join(rule.sender_domain_is)}." + report.status_extended = f"Transport rule {rule.name} whitelists domains: {', '.join(rule.sender_domain_is)}." findings.append(report) diff --git a/tests/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled_test.py b/tests/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled_test.py new file mode 100644 index 0000000000..557461d935 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_external_email_tagging_enabled/exchange_external_email_tagging_enabled_test.py @@ -0,0 +1,173 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_external_email_tagging_enabled: + def test_external_tagging_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled import ( + exchange_external_email_tagging_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + ExternalMailConfig, + ) + + exchange_client.external_mail_config = [ + ExternalMailConfig(identity="Org1", external_mail_tag_enabled=True) + ] + + check = exchange_external_email_tagging_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External sender tagging is enabled for Exchange identity Org1." + ) + assert result[0].resource == exchange_client.external_mail_config[0].dict() + assert result[0].resource_name == "Org1" + assert result[0].resource_id == "Org1" + assert result[0].location == "global" + + def test_external_tagging_disabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled import ( + exchange_external_email_tagging_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + ExternalMailConfig, + ) + + exchange_client.external_mail_config = [ + ExternalMailConfig(identity="Org2", external_mail_tag_enabled=False) + ] + + check = exchange_external_email_tagging_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External sender tagging is disabled for Exchange identity Org2." + ) + assert result[0].resource == exchange_client.external_mail_config[0].dict() + assert result[0].resource_name == "Org2" + assert result[0].resource_id == "Org2" + assert result[0].location == "global" + + def test_multiple_configs_mixed_status(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled import ( + exchange_external_email_tagging_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + ExternalMailConfig, + ) + + exchange_client.external_mail_config = [ + ExternalMailConfig( + identity="OrgEnabled", external_mail_tag_enabled=True + ), + ExternalMailConfig( + identity="OrgDisabled", external_mail_tag_enabled=False + ), + ] + + check = exchange_external_email_tagging_enabled() + result = check.execute() + + assert len(result) == 2 + + assert result[0].status == "PASS" + assert result[0].resource_name == "OrgEnabled" + assert ( + result[0].status_extended + == "External sender tagging is enabled for Exchange identity OrgEnabled." + ) + + assert result[1].status == "FAIL" + assert result[1].resource_name == "OrgDisabled" + assert ( + result[1].status_extended + == "External sender tagging is disabled for Exchange identity OrgDisabled." + ) + + def test_no_mail_configs(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_external_email_tagging_enabled.exchange_external_email_tagging_enabled import ( + exchange_external_email_tagging_enabled, + ) + + exchange_client.external_mail_config = [] + + check = exchange_external_email_tagging_enabled() + result = check.execute() + + assert len(result) == 0 diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 1d74474e3d..8131157265 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -4,6 +4,7 @@ from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, + ExternalMailConfig, MailboxAuditConfig, Organization, TransportRule, @@ -22,6 +23,19 @@ def mock_exchange_get_mailbox_audit_config(_): ] +def mock_exchange_get_external_mail_config(_): + return [ + ExternalMailConfig( + identity="test", + external_mail_tag_enabled=True, + ), + ExternalMailConfig( + identity="test2", + external_mail_tag_enabled=False, + ), + ] + + def mock_exchange_get_transport_rules(_): return [ TransportRule( @@ -101,6 +115,29 @@ class Test_Exchange_Service: exchange_client.powershell.close() + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_external_mail_config", + new=mock_exchange_get_external_mail_config, + ) + def test_get_external_mail_config(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + external_mail_config = exchange_client.external_mail_config + assert len(external_mail_config) == 2 + assert external_mail_config[0].identity == "test" + assert external_mail_config[0].external_mail_tag_enabled is True + assert external_mail_config[1].identity == "test2" + assert external_mail_config[1].external_mail_tag_enabled is False + exchange_client.powershell.close() + @patch( "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_transport_rules", new=mock_exchange_get_transport_rules, diff --git a/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py b/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py index ad51a64b58..daea4fd1de 100644 --- a/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py +++ b/tests/providers/m365/services/exchange/exchange_transport_rules_whitelist_disabled/exchange_transport_rules_whitelist_disabled_test.py @@ -41,14 +41,14 @@ class Test_exchange_transport_rules_whitelist_disabled: assert result[0].status == "PASS" assert ( result[0].status_extended - == "Transport rule 'Rule1' does not whitelist any domains." + == "Transport rule Rule1 does not whitelist any domains." ) assert result[0].resource_name == "Rule1" assert result[0].resource_id == "ExchangeTransportRule" assert result[1].status == "PASS" assert ( result[1].status_extended - == "Transport rule 'Rule2' does not whitelist any domains." + == "Transport rule Rule2 does not whitelist any domains." ) assert result[1].resource_name == "Rule2" @@ -91,7 +91,7 @@ class Test_exchange_transport_rules_whitelist_disabled: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Transport rule 'WhitelistRule' whitelists domains: whitelist.com." + == "Transport rule WhitelistRule whitelists domains: whitelist.com." ) assert result[0].resource_name == "WhitelistRule" assert result[0].resource_id == "ExchangeTransportRule" @@ -99,7 +99,7 @@ class Test_exchange_transport_rules_whitelist_disabled: assert result[1].status == "PASS" assert ( result[1].status_extended - == "Transport rule 'NoWhitelistRule' does not whitelist any domains." + == "Transport rule NoWhitelistRule does not whitelist any domains." ) assert result[1].resource_name == "NoWhitelistRule" assert result[1].resource_id == "ExchangeTransportRule" From 87f3e0a138b71a136ca1c3f857a836caa885aef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 24 Apr 2025 13:21:52 +0200 Subject: [PATCH 211/359] fix(nhn): remove unneeded parameter (#7600) --- prowler/CHANGELOG.md | 1 + prowler/__main__.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 1bb4df58ab..ccdfc5abc8 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). - Update S3 bucket naming validation to accept dots [(#7545)](https://github.com/prowler-cloud/prowler/pull/7545). - Handle new FlowLog model properties in Azure [(#7546)](https://github.com/prowler-cloud/prowler/pull/7546). +- Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) --- diff --git a/prowler/__main__.py b/prowler/__main__.py index 3bacaf291f..13b430e764 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -717,7 +717,6 @@ def prowler(): generic_compliance = GenericCompliance( findings=finding_outputs, compliance=bulk_compliance_frameworks[compliance_name], - create_file_descriptor=True, file_path=filename, ) generated_outputs["compliance"].append(generic_compliance) From eaf0d06b631bc9e480721e7e01766a6b8fe646c1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:20:58 +0200 Subject: [PATCH 212/359] chore(m365): add `test_connection` function (#7541) Co-authored-by: MrCloudSec --- .../providers/m365/exceptions/exceptions.py | 37 ++- .../m365/lib/powershell/m365_powershell.py | 21 +- prowler/providers/m365/m365_provider.py | 123 ++++++++-- prowler/providers/m365/models.py | 1 + .../lib/powershell/m365_powershell_test.py | 92 ++++++- tests/providers/m365/m365_provider_test.py | 232 +++++++++++++++--- 6 files changed, 447 insertions(+), 59 deletions(-) diff --git a/prowler/providers/m365/exceptions/exceptions.py b/prowler/providers/m365/exceptions/exceptions.py index 9f9c96a178..2b5840dd10 100644 --- a/prowler/providers/m365/exceptions/exceptions.py +++ b/prowler/providers/m365/exceptions/exceptions.py @@ -94,7 +94,7 @@ class M365BaseException(ProwlerException): "message": "Tenant Id is required for Microsoft 365 static credentials. Make sure you are using the correct credentials.", "remediation": "Check the Microsoft 365 Tenant ID and ensure it is properly set up.", }, - (6022, "M365MissingEnvironmentUserCredentialsError"): { + (6022, "M365MissingEnvironmentCredentialsError"): { "message": "User and Password environment variables are needed to use Credentials authentication method.", "remediation": "Ensure your environment variables are properly set up.", }, @@ -102,6 +102,18 @@ class M365BaseException(ProwlerException): "message": "User or Password environment variables are not correct.", "remediation": "Ensure you are using the right credentials.", }, + (6024, "M365NotValidUserError"): { + "message": "The provided M365 User is not valid.", + "remediation": "Check the M365 User and ensure it is a valid user.", + }, + (6025, "M365NotValidEncryptedPasswordError"): { + "message": "The provided M365 Encrypted Password is not valid.", + "remediation": "Check the M365 Encrypted Password and ensure it is a valid password.", + }, + (6026, "M365UserNotBelongingToTenantError"): { + "message": "The provided M365 User does not belong to the specified tenant.", + "remediation": "Check the M365 User email domain and ensure it belongs to the specified tenant.", + }, } def __init__(self, code, file=None, original_exception=None, message=None): @@ -279,7 +291,7 @@ class M365NotTenantIdButClientIdAndClientSecretError(M365CredentialsError): ) -class M365MissingEnvironmentUserCredentialsError(M365CredentialsError): +class M365MissingEnvironmentCredentialsError(M365CredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( 6022, file=file, original_exception=original_exception, message=message @@ -291,3 +303,24 @@ class M365EnvironmentUserCredentialsError(M365CredentialsError): super().__init__( 6023, file=file, original_exception=original_exception, message=message ) + + +class M365NotValidUserError(M365CredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 6024, file=file, original_exception=original_exception, message=message + ) + + +class M365NotValidEncryptedPasswordError(M365CredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 6025, file=file, original_exception=original_exception, message=message + ) + + +class M365UserNotBelongingToTenantError(M365CredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 6026, file=file, original_exception=original_exception, message=message + ) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 8e4df5b94d..b3a7db9689 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -1,6 +1,11 @@ +import os + import msal from prowler.lib.powershell.powershell import PowerShellSession +from prowler.providers.m365.exceptions.exceptions import ( + M365UserNotBelongingToTenantError, +) from prowler.providers.m365.models import M365Credentials @@ -102,7 +107,21 @@ class M365PowerShell(PowerShellSession): scopes=["https://graph.microsoft.com/.default"], ) - return "access_token" in result + if result is None: + return False + + if "access_token" not in result: + return False + + # Validate user credentials belong to tenant + user_domain = credentials.user.split("@")[1] + if not credentials.provider_id.endswith(user_domain): + raise M365UserNotBelongingToTenantError( + file=os.path.basename(__file__), + message="The provided M365 User does not belong to the specified tenant.", + ) + + return True def connect_microsoft_teams(self) -> dict: """ diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py index cd4438da72..8608c88180 100644 --- a/prowler/providers/m365/m365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -1,6 +1,5 @@ import asyncio import os -import re from argparse import ArgumentTypeError from os import getenv from uuid import UUID @@ -40,12 +39,14 @@ from prowler.providers.m365.exceptions.exceptions import ( M365HTTPResponseError, M365InteractiveBrowserCredentialError, M365InvalidProviderIdError, - M365MissingEnvironmentUserCredentialsError, + M365MissingEnvironmentCredentialsError, M365NoAuthenticationMethodError, M365NotTenantIdButClientIdAndClientSecretError, M365NotValidClientIdError, M365NotValidClientSecretError, + M365NotValidEncryptedPasswordError, M365NotValidTenantIdError, + M365NotValidUserError, M365SetUpRegionConfigError, M365SetUpSessionError, M365TenantIdAndClientIdNotBelongingToClientSecretError, @@ -105,10 +106,10 @@ class M365Provider(Provider): def __init__( self, - sp_env_auth: bool, - env_auth: bool, - az_cli_auth: bool, - browser_auth: bool, + sp_env_auth: bool = False, + env_auth: bool = False, + az_cli_auth: bool = False, + browser_auth: bool = False, tenant_id: str = None, client_id: str = None, client_secret: str = None, @@ -187,9 +188,6 @@ class M365Provider(Provider): self._region_config, ) - # Set up PowerShell session credentials - self._credentials = self.setup_powershell(env_auth, m365_credentials) - # Set up the identity self._identity = self.setup_identity( az_cli_auth, @@ -199,6 +197,13 @@ class M365Provider(Provider): client_id, ) + # Set up PowerShell session credentials + self._credentials = self.setup_powershell( + env_auth=env_auth, + m365_credentials=m365_credentials, + provider_id=self.identity.tenant_domain, + ) + # Audit Config if config_content: self._audit_config = config_content @@ -294,8 +299,8 @@ class M365Provider(Provider): M365BrowserAuthNoTenantIDError: If browser authentication is enabled but the tenant ID is not found. """ - if not client_id and not client_secret and not user and not encrypted_password: - if not browser_auth and tenant_id: + if not client_id and not client_secret: + if not browser_auth and tenant_id and not env_auth: raise M365BrowserAuthNoFlagError( file=os.path.basename(__file__), message="M365 tenant ID error: browser authentication flag (--browser-auth) not found", @@ -315,6 +320,12 @@ class M365Provider(Provider): file=os.path.basename(__file__), message="M365 Tenant ID (--tenant-id) is required for browser authentication mode", ) + elif env_auth: + if not user or not encrypted_password or not tenant_id: + raise M365MissingEnvironmentCredentialsError( + file=os.path.basename(__file__), + message="M365 provider requires AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID, M365_USER and M365_ENCRYPTED_PASSWORD environment variables to be set when using --env-auth", + ) else: if not tenant_id: raise M365NotTenantIdButClientIdAndClientSecretError( @@ -362,7 +373,7 @@ class M365Provider(Provider): @staticmethod def setup_powershell( - env_auth: bool = False, m365_credentials: dict = {} + env_auth: bool = False, m365_credentials: dict = {}, provider_id: str = None ) -> M365Credentials: """Gets the M365 credentials. @@ -382,6 +393,7 @@ class M365Provider(Provider): client_id=m365_credentials.get("client_id", ""), client_secret=m365_credentials.get("client_secret", ""), tenant_id=m365_credentials.get("tenant_id", ""), + provider_id=provider_id, ) elif env_auth: m365_user = getenv("M365_USER") @@ -394,7 +406,7 @@ class M365Provider(Provider): logger.critical( "M365 provider: Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables needed for credentials authentication" ) - raise M365MissingEnvironmentUserCredentialsError( + raise M365MissingEnvironmentCredentialsError( file=os.path.basename(__file__), message="Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication.", ) @@ -404,6 +416,7 @@ class M365Provider(Provider): client_id=client_id, client_secret=client_secret, tenant_id=tenant_id, + provider_id=provider_id, ) if credentials: @@ -466,6 +479,9 @@ class M365Provider(Provider): - tenant_id: The M365 Active Directory tenant ID. - client_id: The M365 client ID. - client_secret: The M365 client secret + - user: The M365 user email + - encrypted_password: The M365 encrypted password + - provider_id: The M365 provider ID (in this case the Tenant ID). region_config (M365RegionConfig): The region configuration object. Returns: @@ -592,10 +608,11 @@ class M365Provider(Provider): client_secret=None, user=None, encrypted_password=None, + provider_id=None, ) -> Connection: - """Test connection to M365 subscription. + """Test connection to M365 tenant and PowerShell modules. - Test the connection to an M365 subscription using the provided credentials. + Test the connection to an M365 tenant and PowerShell modules using the provided credentials. Args: @@ -610,6 +627,7 @@ class M365Provider(Provider): client_secret (str): The M365 client secret. user (str): The M365 user email. encrypted_password (str): The M365 encrypted_password. + provider_id (str): The M365 provider ID (in this case the Tenant ID). Returns: @@ -622,7 +640,7 @@ class M365Provider(Provider): M365InteractiveBrowserCredentialError: If there is an error in retrieving the M365 credentials using browser authentication. M365HTTPResponseError: If there is an HTTP response error. M365ConfigCredentialsError: If there is an error in configuring the M365 credentials from a dictionary. - + M365InvalidProviderIdError: If the provider ID does not match the application tenant domain. Examples: >>> M365Provider.test_connection(az_cli_auth=True) @@ -649,11 +667,22 @@ class M365Provider(Provider): # Get the dict from the static credentials m365_credentials = None if tenant_id and client_id and client_secret: - m365_credentials = M365Provider.validate_static_credentials( - tenant_id=tenant_id, - client_id=client_id, - client_secret=client_secret, - ) + if not user and not encrypted_password: + m365_credentials = M365Provider.validate_static_credentials( + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + user="user", + encrypted_password="encrypted_password", + ) + else: + m365_credentials = M365Provider.validate_static_credentials( + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + user=user, + encrypted_password=encrypted_password, + ) # Set up the M365 session credentials = M365Provider.setup_session( @@ -668,7 +697,30 @@ class M365Provider(Provider): GraphServiceClient(credentials=credentials) - logger.info("M365 provider: Connection to M365 successful") + logger.info("M365 provider: Connection to MSGraph successful") + + # Set up PowerShell credentials + if user and encrypted_password: + M365Provider.setup_powershell( + env_auth, + m365_credentials, + provider_id, + ) + else: + logger.info( + "M365 provider: Connection to PowerShell has not been requested" + ) + + logger.info("M365 provider: Connection to PowerShell successful") + + # Check that user domain, provider_id and Graph client tenant_domain are the same + if user and encrypted_password: + user_domain = user.split("@")[1] + if provider_id and user_domain != provider_id: + raise M365InvalidProviderIdError( + file=os.path.basename(__file__), + message=f"Provider ID {provider_id} does not match Application tenant domain {user_domain}", + ) return Connection(is_connected=True) @@ -896,7 +948,11 @@ class M365Provider(Provider): @staticmethod def validate_static_credentials( - tenant_id: str = None, client_id: str = None, client_secret: str = None + tenant_id: str = None, + client_id: str = None, + client_secret: str = None, + user: str = None, + encrypted_password: str = None, ) -> dict: """ Validates the static credentials for the M365 provider. @@ -905,6 +961,8 @@ class M365Provider(Provider): tenant_id (str): The M365 Active Directory tenant ID. client_id (str): The M365 client ID. client_secret (str): The M365 client secret. + user (str): The M365 user email. + encrypted_password (str): The M365 encrypted password. Raises: M365NotValidTenantIdError: If the provided M365 Tenant ID is not valid. @@ -934,19 +992,36 @@ class M365Provider(Provider): file=os.path.basename(__file__), message="The provided M365 Client ID is not valid.", ) + # Validate the Client Secret - if not re.match("^[a-zA-Z0-9._~-]+$", client_secret): + if not client_secret: raise M365NotValidClientSecretError( file=os.path.basename(__file__), message="The provided M365 Client Secret is not valid.", ) + # Validate the User + if not user: + raise M365NotValidUserError( + file=os.path.basename(__file__), + message="The provided M365 User is not valid.", + ) + + # Validate the Encrypted Password + if not encrypted_password: + raise M365NotValidEncryptedPasswordError( + file=os.path.basename(__file__), + message="The provided M365 Encrypted Password is not valid.", + ) + try: M365Provider.verify_client(tenant_id, client_id, client_secret) return { "tenant_id": tenant_id, "client_id": client_id, "client_secret": client_secret, + "user": user, + "encrypted_password": encrypted_password, } except M365NotValidTenantIdError as tenant_id_error: logger.error( diff --git a/prowler/providers/m365/models.py b/prowler/providers/m365/models.py index f260653555..a2e3b68151 100644 --- a/prowler/providers/m365/models.py +++ b/prowler/providers/m365/models.py @@ -25,6 +25,7 @@ class M365Credentials(BaseModel): client_id: str = "" client_secret: str = "" tenant_id: str = "" + provider_id: str = "" class M365OutputOptions(ProviderOutputOptions): diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py index f32cc1c780..56cc28ef33 100644 --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -1,5 +1,10 @@ from unittest.mock import MagicMock, patch +import pytest + +from prowler.providers.m365.exceptions.exceptions import ( + M365UserNotBelongingToTenantError, +) from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell from prowler.providers.m365.models import M365Credentials @@ -84,11 +89,12 @@ class Testm365PowerShell: } credentials = M365Credentials( - user="test@example.com", + user="test@contoso.onmicrosoft.com", passwd="test_password", client_id="test_client_id", client_secret="test_client_secret", tenant_id="test_tenant_id", + provider_id="contoso.onmicrosoft.com", ) session = M365PowerShell(credentials) @@ -115,7 +121,89 @@ class Testm365PowerShell: authority="https://login.microsoftonline.com/test_tenant_id", ) mock_msal_instance.acquire_token_by_username_password.assert_called_once_with( - username="test@example.com", + username="test@contoso.onmicrosoft.com", + password="decrypted_password", + scopes=["https://graph.microsoft.com/.default"], + ) + session.close() + + @patch("subprocess.Popen") + @patch("msal.ConfidentialClientApplication") + def test_test_credentials_user_not_belonging_to_tenant(self, mock_msal, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + mock_msal_instance = MagicMock() + mock_msal.return_value = mock_msal_instance + mock_msal_instance.acquire_token_by_username_password.return_value = { + "access_token": "test_token" + } + + credentials = M365Credentials( + user="user@otherdomain.com", + passwd="test_password", + client_id="test_client_id", + client_secret="test_client_secret", + tenant_id="test_tenant_id", + provider_id="contoso.onmicrosoft.com", + ) + session = M365PowerShell(credentials) + + session.execute = MagicMock() + session.process.stdin.write = MagicMock() + session.read_output = MagicMock(return_value="decrypted_password") + + with pytest.raises(M365UserNotBelongingToTenantError) as exception: + session.test_credentials(credentials) + + assert exception.type == M365UserNotBelongingToTenantError + assert "The provided M365 User does not belong to the specified tenant." in str( + exception.value + ) + + mock_msal.assert_called_once_with( + client_id="test_client_id", + client_credential="test_client_secret", + authority="https://login.microsoftonline.com/test_tenant_id", + ) + mock_msal_instance.acquire_token_by_username_password.assert_called_once_with( + username="user@otherdomain.com", + password="decrypted_password", + scopes=["https://graph.microsoft.com/.default"], + ) + session.close() + + @patch("subprocess.Popen") + @patch("msal.ConfidentialClientApplication") + def test_test_credentials_auth_failure(self, mock_msal, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + mock_msal_instance = MagicMock() + mock_msal.return_value = mock_msal_instance + mock_msal_instance.acquire_token_by_username_password.return_value = None + + credentials = M365Credentials( + user="test@contoso.onmicrosoft.com", + passwd="test_password", + client_id="test_client_id", + client_secret="test_client_secret", + tenant_id="test_tenant_id", + provider_id="contoso.onmicrosoft.com", + ) + session = M365PowerShell(credentials) + + session.execute = MagicMock() + session.process.stdin.write = MagicMock() + session.read_output = MagicMock(return_value="decrypted_password") + + assert session.test_credentials(credentials) is False + + mock_msal.assert_called_once_with( + client_id="test_client_id", + client_credential="test_client_secret", + authority="https://login.microsoftonline.com/test_tenant_id", + ) + mock_msal_instance.acquire_token_by_username_password.assert_called_once_with( + username="test@contoso.onmicrosoft.com", password="decrypted_password", scopes=["https://graph.microsoft.com/.default"], ) diff --git a/tests/providers/m365/m365_provider_test.py b/tests/providers/m365/m365_provider_test.py index 22f0bef4b0..9fc991b60f 100644 --- a/tests/providers/m365/m365_provider_test.py +++ b/tests/providers/m365/m365_provider_test.py @@ -1,3 +1,4 @@ +import os from unittest.mock import patch from uuid import uuid4 @@ -18,8 +19,15 @@ from prowler.config.config import ( from prowler.providers.common.models import Connection from prowler.providers.m365.exceptions.exceptions import ( M365HTTPResponseError, - M365MissingEnvironmentUserCredentialsError, + M365InvalidProviderIdError, + M365MissingEnvironmentCredentialsError, M365NoAuthenticationMethodError, + M365NotValidClientIdError, + M365NotValidClientSecretError, + M365NotValidEncryptedPasswordError, + M365NotValidTenantIdError, + M365NotValidUserError, + M365UserNotBelongingToTenantError, ) from prowler.providers.m365.m365_provider import M365Provider from prowler.providers.m365.models import ( @@ -333,37 +341,59 @@ class TestM365Provider: assert test_connection.is_connected assert test_connection.error is None - def test_test_connection_tenant_id_client_id_client_secret_user_encrypted_password( + def test_test_connection_tenant_id_client_id_client_secret_no_user_encrypted_password( self, ): - with ( - patch( - "prowler.providers.m365.m365_provider.M365Provider.setup_session" - ) as mock_setup_session, - patch( - "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" - ) as mock_validate_static_credentials, - ): - # Mock setup_session to return a mocked session object - mock_session = MagicMock() - mock_setup_session.return_value = mock_session - - # Mock ValidateStaticCredentials to avoid real API calls - mock_validate_static_credentials.return_value = None - - test_connection = M365Provider.test_connection( - tenant_id=str(uuid4()), - region="M365Global", - raise_on_exception=False, - client_id=str(uuid4()), - client_secret=str(uuid4()), - user="user@user.com", - encrypted_password="AAAA1111", + with patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials: + mock_validate_static_credentials.side_effect = M365NotValidUserError( + file=os.path.basename(__file__), + message="The provided M365 User is not valid.", ) - assert isinstance(test_connection, Connection) - assert test_connection.is_connected - assert test_connection.error is None + with pytest.raises(M365NotValidUserError) as exception: + M365Provider.test_connection( + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=True, + client_id=str(uuid4()), + client_secret=str(uuid4()), + user=None, + encrypted_password="test_password", + ) + + assert exception.type == M365NotValidUserError + assert "The provided M365 User is not valid." in str(exception.value) + + def test_test_connection_tenant_id_client_id_client_secret_user_no_encrypted_password( + self, + ): + with patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials: + mock_validate_static_credentials.side_effect = ( + M365NotValidEncryptedPasswordError( + file=os.path.basename(__file__), + message="The provided M365 Encrypted Password is not valid.", + ) + ) + + with pytest.raises(M365NotValidEncryptedPasswordError) as exception: + M365Provider.test_connection( + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=True, + client_id=str(uuid4()), + client_secret=str(uuid4()), + user="test@example.com", + encrypted_password=None, + ) + + assert exception.type == M365NotValidEncryptedPasswordError + assert "The provided M365 Encrypted Password is not valid." in str( + exception.value + ) def test_test_connection_with_httpresponseerror(self): with patch( @@ -424,7 +454,9 @@ class TestM365Provider: return_value=True, ): result = M365Provider.setup_powershell( - env_auth=False, m365_credentials=credentials_dict + env_auth=False, + m365_credentials=credentials_dict, + provider_id="test_provider_id", ) assert result.user == credentials_dict["user"] @@ -440,7 +472,7 @@ class TestM365Provider: mock_session.test_credentials.return_value = False mock_powershell.return_value = mock_session - with pytest.raises(M365MissingEnvironmentUserCredentialsError) as exc_info: + with pytest.raises(M365MissingEnvironmentCredentialsError) as exc_info: M365Provider.setup_powershell( env_auth=True, m365_credentials=credentials ) @@ -450,3 +482,143 @@ class TestM365Provider: in str(exc_info.value) ) mock_session.test_credentials.assert_not_called() + + def test_test_connection_user_not_belonging_to_tenant( + self, + ): + with patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials: + mock_validate_static_credentials.side_effect = M365UserNotBelongingToTenantError( + file=os.path.basename(__file__), + message="The provided M365 User does not belong to the specified tenant.", + ) + + with pytest.raises(M365UserNotBelongingToTenantError) as exception: + M365Provider.test_connection( + tenant_id="contoso.onmicrosoft.com", + region="M365Global", + raise_on_exception=True, + client_id=str(uuid4()), + client_secret=str(uuid4()), + user="user@otherdomain.com", + encrypted_password="test_password", + ) + + assert exception.type == M365UserNotBelongingToTenantError + assert ( + "The provided M365 User does not belong to the specified tenant." + in str(exception.value) + ) + + def test_validate_static_credentials_invalid_tenant_id(self): + with pytest.raises(M365NotValidTenantIdError) as exception: + M365Provider.validate_static_credentials( + tenant_id="invalid-tenant-id", + client_id="12345678-1234-5678-1234-567812345678", + client_secret="test_secret", + user="test@example.com", + encrypted_password="test_password", + ) + assert "The provided M365 Tenant ID is not valid." in str(exception.value) + + def test_validate_static_credentials_missing_client_id(self): + with pytest.raises(M365NotValidClientIdError) as exception: + M365Provider.validate_static_credentials( + tenant_id="12345678-1234-5678-1234-567812345678", + client_id="", + client_secret="test_secret", + user="test@example.com", + encrypted_password="test_password", + ) + assert "The provided M365 Client ID is not valid." in str(exception.value) + + def test_validate_static_credentials_missing_client_secret(self): + with pytest.raises(M365NotValidClientSecretError) as exception: + M365Provider.validate_static_credentials( + tenant_id="12345678-1234-5678-1234-567812345678", + client_id="12345678-1234-5678-1234-567812345678", + client_secret="", + user="test@example.com", + encrypted_password="test_password", + ) + assert "The provided M365 Client Secret is not valid." in str(exception.value) + + def test_validate_static_credentials_missing_user(self): + with pytest.raises(M365NotValidUserError) as exception: + M365Provider.validate_static_credentials( + tenant_id="12345678-1234-5678-1234-567812345678", + client_id="12345678-1234-5678-1234-567812345678", + client_secret="test_secret", + user="", + encrypted_password="test_password", + ) + assert "The provided M365 User is not valid." in str(exception.value) + + def test_validate_static_credentials_missing_encrypted_password(self): + with pytest.raises(M365NotValidEncryptedPasswordError) as exception: + M365Provider.validate_static_credentials( + tenant_id="12345678-1234-5678-1234-567812345678", + client_id="12345678-1234-5678-1234-567812345678", + client_secret="test_secret", + user="test@example.com", + encrypted_password="", + ) + assert "The provided M365 Encrypted Password is not valid." in str( + exception.value + ) + + def test_validate_arguments_missing_env_credentials(self): + with pytest.raises(M365MissingEnvironmentCredentialsError) as exception: + M365Provider.validate_arguments( + az_cli_auth=False, + sp_env_auth=False, + env_auth=True, + browser_auth=False, + tenant_id=None, + client_id="test_client_id", + client_secret="test_secret", + user=None, + encrypted_password=None, + ) + assert ( + "M365 provider requires AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID, M365_USER and M365_ENCRYPTED_PASSWORD environment variables to be set when using --env-auth" + in str(exception.value) + ) + + def test_test_connection_invalid_provider_id(self): + with ( + patch( + "prowler.providers.m365.m365_provider.M365Provider.setup_session" + ) as mock_setup_session, + patch( + "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials" + ) as mock_validate_static_credentials, + ): + # Mock setup_session to return a mocked session object + mock_session = MagicMock() + mock_setup_session.return_value = mock_session + + # Mock ValidateStaticCredentials to avoid real API calls + mock_validate_static_credentials.return_value = None + + user_domain = "contoso.com" + provider_id = "Test.com" + + with pytest.raises(M365InvalidProviderIdError) as exception: + M365Provider.test_connection( + tenant_id=str(uuid4()), + region="M365Global", + raise_on_exception=True, + client_id=str(uuid4()), + client_secret=str(uuid4()), + user=f"user@{user_domain}", + encrypted_password="test_password", + provider_id=provider_id, + ) + + assert exception.type == M365InvalidProviderIdError + assert ( + f"Provider ID {provider_id} does not match Application tenant domain {user_domain}" + in str(exception.value) + ) From b129326ed60ecd9e044823c82b4260c5df884bc2 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Thu, 24 Apr 2025 20:10:36 +0545 Subject: [PATCH 213/359] chore(actions): Bump Prowler version on release (#7560) --- .github/workflows/sdk-bump-version.yml | 94 ++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/sdk-bump-version.yml diff --git a/.github/workflows/sdk-bump-version.yml b/.github/workflows/sdk-bump-version.yml new file mode 100644 index 0000000000..bc28afa1e4 --- /dev/null +++ b/.github/workflows/sdk-bump-version.yml @@ -0,0 +1,94 @@ +name: SDK - Bump Version + +on: + release: + types: [published] + + +env: + PROWLER_VERSION: ${{ github.event.release.tag_name }} + BASE_BRANCH: master + +jobs: + bump-version: + name: Bump Version + if: github.repository == 'prowler-cloud/prowler' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Get Prowler version + shell: bash + run: | + if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + MAJOR_VERSION=${BASH_REMATCH[1]} + MINOR_VERSION=${BASH_REMATCH[2]} + FIX_VERSION=${BASH_REMATCH[3]} + + if (( MAJOR_VERSION == 5 )); then + if (( FIX_VERSION == 0 )); then + echo "Minor Release: $PROWLER_VERSION" + + BUMP_VERSION_TO=${MAJOR_VERSION}.$((MINOR_VERSION + 1)).${FIX_VERSION} + echo "BUMP_VERSION_TO=${BUMP_VERSION_TO}" >> "${GITHUB_ENV}" + + TARGET_BRANCH=${BASE_BRANCH} + echo "TARGET_BRANCH=${TARGET_BRANCH}" >> "${GITHUB_ENV}" + + echo "Bumping to next minor version: ${BUMP_VERSION_TO} in branch ${TARGET_BRANCH}" + else + echo "Patch Release: $PROWLER_VERSION" + + BUMP_VERSION_TO=${MAJOR_VERSION}.${MINOR_VERSION}.$((FIX_VERSION + 1)) + echo "BUMP_VERSION_TO=${BUMP_VERSION_TO}" >> "${GITHUB_ENV}" + + TARGET_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION} + echo "TARGET_BRANCH=${TARGET_BRANCH}" >> "${GITHUB_ENV}" + + echo "Bumping to next patch version: ${BUMP_VERSION_TO} in branch ${TARGET_BRANCH}" + fi + else + echo "Releasing another Prowler major version, aborting..." + exit 1 + fi + else + echo "Invalid version syntax: '$PROWLER_VERSION' (must be N.N.N)" >&2 + exit 1 + fi + + - name: Bump versions in files + run: | + echo "Using PROWLER_VERSION=$PROWLER_VERSION" + echo "Using BUMP_VERSION_TO=$BUMP_VERSION_TO" + + set -e + + echo "Bumping version in pyproject.toml ..." + sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${BUMP_VERSION_TO}\"|" pyproject.toml + + echo "Bumping version in prowler/config/config.py ..." + sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${BUMP_VERSION_TO}\"|" prowler/config/config.py + + echo "Bumping version in .env ..." + sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${BUMP_VERSION_TO}|" .env + + git --no-pager diff + + + - name: Create Pull Request + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + with: + author: prowler-bot <179230569+prowler-bot@users.noreply.github.com> + token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} + base: ${{ env.TARGET_BRANCH }} + commit-message: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}" + branch: "version-bump-to-v${{ env.BUMP_VERSION_TO }}" + title: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}" + body: | + ### Description + + Bump Prowler version to v${{ env.BUMP_VERSION_TO }} + + ### License + + By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. From f85450d0b51c300a851453771df52276762eaac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 24 Apr 2025 17:23:24 +0200 Subject: [PATCH 214/359] fix(html): remove first empty line (#7606) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 3 ++- prowler/lib/outputs/html/html.py | 3 +-- tests/lib/outputs/html/html_test.py | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index ccdfc5abc8..255d321cc0 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -36,7 +36,8 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). - Update S3 bucket naming validation to accept dots [(#7545)](https://github.com/prowler-cloud/prowler/pull/7545). - Handle new FlowLog model properties in Azure [(#7546)](https://github.com/prowler-cloud/prowler/pull/7546). -- Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) +- Remove first empty line in HTML output [(#7606)](https://github.com/prowler-cloud/prowler/pull/7606) +- Remove invalid parameter `create_file_descriptor` in NHN provider [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) --- diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index d9177a4ab9..aeb11aebfc 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -106,8 +106,7 @@ class HTML(Output): """ try: file_descriptor.write( - f""" - + f""" diff --git a/tests/lib/outputs/html/html_test.py b/tests/lib/outputs/html/html_test.py index c9fe3ddba9..2bc6d9ab07 100644 --- a/tests/lib/outputs/html/html_test.py +++ b/tests/lib/outputs/html/html_test.py @@ -233,8 +233,7 @@ def get_aws_html_header(args: list) -> str: Returns: str: HTML header for AWS """ - aws_html_header = f""" - + aws_html_header = f""" From d9782c7b8a9e63c4f7dbcf9d60994f7cb2f83b9f Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:13:42 +0200 Subject: [PATCH 215/359] feat(teams): add new check `teams_meeting_external_lobby_bypass_disabled` (#7568) Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ternal_lobby_bypass_disabled.metadata.json | 30 +++ ..._meeting_external_lobby_bypass_disabled.py | 52 +++++ .../m365/services/teams/teams_service.py | 4 + ...ing_external_lobby_bypass_disabled_test.py | 206 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 295 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 255d321cc0..13422904fb 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492) - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) - Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567) +- Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.metadata.json new file mode 100644 index 0000000000..7bbc9b0a54 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_external_lobby_bypass_disabled", + "CheckTitle": "Ensure only people in the organization can bypass the lobby.", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure only people in the organization can bypass the lobby.", + "Risk": "Allowing external users or unauthenticated participants to bypass the lobby increases the risk of unauthorized access to sensitive meetings and potential disruptions. It may also lead to unscheduled meetings being initiated by external parties.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AutoAdmittedUsers 'EveryoneInCompanyExcludingGuests' ", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting join & lobby set Who can bypass the lobby to People in my org.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that only people within the organization can bypass the lobby, requiring external users and dial-in participants to wait for approval from an organizer, co-organizer, or presenter. This helps secure sensitive meetings and prevents unauthorized access.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.py new file mode 100644 index 0000000000..53796008f5 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled.py @@ -0,0 +1,52 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_external_lobby_bypass_disabled(Check): + """Check if only people in the organization can bypass the lobby. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for only people in the organization can bypass the lobby. + + This method checks if only people in the organization can bypass the lobby. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "People outside the organization can bypass the lobby." + ) + + allowed_bypass_settings = { + "EveryoneInCompanyExcludingGuests", + "OrganizerOnly", + "InvitedUsers", + } + if ( + global_meeting_policy.allow_external_users_to_bypass_lobby + in allowed_bypass_settings + ): + report.status = "PASS" + report.status_extended = ( + "Only people in the organization can bypass the lobby." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 7231176b9a..2833142ee2 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -52,6 +52,9 @@ class Teams(M365Service): allow_anonymous_users_to_start_meeting=global_meeting_policy.get( "AllowAnonymousUsersToStartMeeting", True ), + allow_external_users_to_bypass_lobby=global_meeting_policy.get( + "AutoAdmittedUsers", "Everyone" + ), ) except Exception as error: logger.error( @@ -95,6 +98,7 @@ class TeamsSettings(BaseModel): class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_join_meeting: bool = True allow_anonymous_users_to_start_meeting: bool = True + allow_external_users_to_bypass_lobby: str = "Everyone" class UserSettings(BaseModel): diff --git a/tests/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled_test.py new file mode 100644 index 0000000000..8fe5d384d4 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_external_lobby_bypass_disabled/teams_meeting_external_lobby_bypass_disabled_test.py @@ -0,0 +1,206 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_external_lobby_bypass_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import ( + teams_meeting_external_lobby_bypass_disabled, + ) + + check = teams_meeting_external_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 0 + + def test_external_users_can_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import ( + teams_meeting_external_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_users_to_bypass_lobby="Everyone" + ) + + check = teams_meeting_external_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "People outside the organization can bypass the lobby." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_only_internal_users_can_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import ( + teams_meeting_external_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests" + ) + + check = teams_meeting_external_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Only people in the organization can bypass the lobby." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_organizer_only_can_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import ( + teams_meeting_external_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_users_to_bypass_lobby="OrganizerOnly" + ) + + check = teams_meeting_external_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Only people in the organization can bypass the lobby." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_invited_users_can_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import ( + teams_meeting_external_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_users_to_bypass_lobby="InvitedUsers" + ) + + check = teams_meeting_external_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Only people in the organization can bypass the lobby." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index a4b523eaf7..d5aab163dc 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -28,6 +28,7 @@ def mock_get_global_meeting_policy(_): return GlobalMeetingPolicy( allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, + allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", ) @@ -122,5 +123,6 @@ class Test_Teams_Service: assert teams_client.global_meeting_policy == GlobalMeetingPolicy( allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, + allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", ) teams_client.powershell.close() From d071dea7f755a77e59cd97c3f69fd02238fe88a0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:05:52 +0200 Subject: [PATCH 216/359] feat(teams): add new check `teams_meeting_dial_in_lobby_bypass_disabled` (#7571) Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ial_in_lobby_bypass_disabled.metadata.json | 30 +++++ ...s_meeting_dial_in_lobby_bypass_disabled.py | 40 +++++++ .../m365/services/teams/teams_service.py | 4 + ...ting_dial_in_lobby_bypass_disabled_test.py | 112 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 189 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 13422904fb..4d3312ef81 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485) - Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567) - Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568) +- Add new check `teams_meeting_dial_in_lobby_bypass_disabled` [(#7571)](https://github.com/prowler-cloud/prowler/pull/7571) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.metadata.json new file mode 100644 index 0000000000..430a0e2277 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_dial_in_lobby_bypass_disabled", + "CheckTitle": "Ensure that dial-in users cannot bypass the lobby in Teams meetings", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure that dial-in users cannot bypass the lobby in Teams meetings", + "Risk": "Allowing dial-in users to bypass the lobby may result in unauthorized or unauthenticated individuals joining sensitive meetings without prior validation, increasing the risk of information leakage or meeting disruptions.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowPSTNUsersToBypassLobby $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting join & lobby set People dialing in can bypass the lobby to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Require all users dialing in by phone to wait in the lobby until admitted by the meeting organizer, co-organizer, or presenter. This ensures proper vetting before granting access to potentially sensitive discussions.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.py new file mode 100644 index 0000000000..0014be6d61 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled.py @@ -0,0 +1,40 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_dial_in_lobby_bypass_disabled(Check): + """Check if users dialing in can't bypass the lobby. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for users dialing in can't bypass the lobby. + + This method checks if users dialing in can't bypass the lobby. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = "Dial-in users can bypass the lobby." + + if not global_meeting_policy.allow_pstn_users_to_bypass_lobby: + report.status = "PASS" + report.status_extended = "Dial-in users cannot bypass the lobby." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 2833142ee2..e3bd078742 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -55,6 +55,9 @@ class Teams(M365Service): allow_external_users_to_bypass_lobby=global_meeting_policy.get( "AutoAdmittedUsers", "Everyone" ), + allow_pstn_users_to_bypass_lobby=global_meeting_policy.get( + "AllowPSTNUsersToBypassLobby", True + ), ) except Exception as error: logger.error( @@ -99,6 +102,7 @@ class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_join_meeting: bool = True allow_anonymous_users_to_start_meeting: bool = True allow_external_users_to_bypass_lobby: str = "Everyone" + allow_pstn_users_to_bypass_lobby: bool = True class UserSettings(BaseModel): diff --git a/tests/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled_test.py new file mode 100644 index 0000000000..c5994b6b8e --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_dial_in_lobby_bypass_disabled/teams_meeting_dial_in_lobby_bypass_disabled_test.py @@ -0,0 +1,112 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_dial_in_lobby_bypass_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled import ( + teams_meeting_dial_in_lobby_bypass_disabled, + ) + + check = teams_meeting_dial_in_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 0 + + def test_dial_in_users_can_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled import ( + teams_meeting_dial_in_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_pstn_users_to_bypass_lobby=True + ) + + check = teams_meeting_dial_in_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == "Dial-in users can bypass the lobby." + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_dial_in_users_cannot_bypass_lobby(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_dial_in_lobby_bypass_disabled.teams_meeting_dial_in_lobby_bypass_disabled import ( + teams_meeting_dial_in_lobby_bypass_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_pstn_users_to_bypass_lobby=False + ) + + check = teams_meeting_dial_in_lobby_bypass_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == "Dial-in users cannot bypass the lobby." + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index d5aab163dc..5ddee2b209 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -29,6 +29,7 @@ def mock_get_global_meeting_policy(_): allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", + allow_pstn_users_to_bypass_lobby=False, ) @@ -124,5 +125,6 @@ class Test_Teams_Service: allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", + allow_pstn_users_to_bypass_lobby=False, ) teams_client.powershell.close() From b076c98ba18553eabdd969894307b7952a327800 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:19:11 -0400 Subject: [PATCH 217/359] chore(deps): bump h11 from 0.14.0 to 0.16.0 (#7609) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/poetry.lock b/poetry.lock index 3f86152cdf..96e4b10349 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4521,6 +4521,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, @@ -4529,6 +4530,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, @@ -4537,6 +4539,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, @@ -4545,6 +4548,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, @@ -4553,6 +4557,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, From d13d2677ea59893703ddb6bb6044fb8eb654b4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 24 Apr 2025 19:28:18 +0200 Subject: [PATCH 218/359] fix(compliance): improve compliance and dashboard (#7596) Co-authored-by: Sergio Garcia --- dashboard/common_methods.py | 347 +++++++++++++++++- ...tected_framework_reliability_pillar_aws.py | 11 +- ...chitected_framework_security_pillar_aws.py | 10 +- dashboard/compliance/kisa_isms_p_2023_aws.py | 11 +- .../compliance/kisa_isms_p_2023_korean_aws.py | 11 +- prowler/CHANGELOG.md | 3 +- .../compliance/aws/kisa_isms_p_2023_aws.json | 332 ++++++++--------- prowler/compliance/azure/cis_2.0_azure.json | 68 ++-- prowler/compliance/azure/cis_2.1_azure.json | 68 ++-- prowler/compliance/azure/cis_3.0_azure.json | 2 +- 10 files changed, 611 insertions(+), 252 deletions(-) diff --git a/dashboard/common_methods.py b/dashboard/common_methods.py index cff28b62d9..338b6e6473 100644 --- a/dashboard/common_methods.py +++ b/dashboard/common_methods.py @@ -2228,13 +2228,356 @@ def get_section_containers_ens(data, section_1, section_2, section_3, section_4) return html.Div(section_containers, className="compliance-data-layout") +def get_section_containers_3_levels(data, section_1, section_2, section_3): + data["STATUS"] = data["STATUS"].apply(map_status_to_icon) + findings_counts_marco = ( + data.groupby([section_1, "STATUS"]).size().unstack(fill_value=0) + ) + section_containers = [] + data[section_1] = data[section_1].astype(str) + data[section_2] = data[section_2].astype(str) + data[section_3] = data[section_3].astype(str) + + data.sort_values( + by=section_3, + key=lambda x: x.map(extract_numeric_values), + ascending=True, + inplace=True, + ) + + for marco in data[section_1].unique(): + success_marco = findings_counts_marco.loc[marco].get(pass_emoji, 0) + failed_marco = findings_counts_marco.loc[marco].get(fail_emoji, 0) + + fig_name = go.Figure( + [ + go.Bar( + name="Failed", + x=[failed_marco], + y=[""], + orientation="h", + marker=dict(color="#e77676"), + width=[0.8], + ), + go.Bar( + name="Success", + x=[success_marco], + y=[""], + orientation="h", + marker=dict(color="#45cc6e"), + width=[0.8], + ), + ] + ) + fig_name.update_layout( + barmode="stack", + margin=dict(l=10, r=10, t=10, b=10), + paper_bgcolor="rgba(0,0,0,0)", + plot_bgcolor="rgba(0,0,0,0)", + showlegend=False, + width=350, + height=30, + xaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + yaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + annotations=[ + dict( + x=success_marco + failed_marco, + y=0, + xref="x", + yref="y", + text=str(success_marco), + showarrow=False, + font=dict(color="#45cc6e", size=14), + xanchor="left", + yanchor="middle", + ), + dict( + x=0, + y=0, + xref="x", + yref="y", + text=str(failed_marco), + showarrow=False, + font=dict(color="#e77676", size=14), + xanchor="right", + yanchor="middle", + ), + ], + ) + fig_name.add_annotation( + x=failed_marco, + y=0.3, + text="|", + showarrow=False, + font=dict(size=20), + xanchor="center", + yanchor="middle", + ) + + graph_div = html.Div( + dcc.Graph( + figure=fig_name, config={"staticPlot": True}, className="info-bar" + ), + className="graph-section", + ) + direct_internal_items = [] + + for categoria in data[data[section_1] == marco][section_2].unique(): + specific_data = data[ + (data[section_1] == marco) & (data[section_2] == categoria) + ] + findings_counts_categoria = ( + specific_data.groupby([section_2, "STATUS"]) + .size() + .unstack(fill_value=0) + ) + success_categoria = findings_counts_categoria.loc[categoria].get( + pass_emoji, 0 + ) + failed_categoria = findings_counts_categoria.loc[categoria].get( + fail_emoji, 0 + ) + + fig_section = go.Figure( + [ + go.Bar( + name="Failed", + x=[failed_categoria], + y=[""], + orientation="h", + marker=dict(color="#e77676"), + width=[0.8], + ), + go.Bar( + name="Success", + x=[success_categoria], + y=[""], + orientation="h", + marker=dict(color="#45cc6e"), + width=[0.8], + ), + ] + ) + fig_section.update_layout( + barmode="stack", + margin=dict(l=10, r=10, t=10, b=10), + paper_bgcolor="rgba(0,0,0,0)", + plot_bgcolor="rgba(0,0,0,0)", + showlegend=False, + width=350, + height=30, + xaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + yaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + annotations=[ + dict( + x=success_categoria + failed_categoria, + y=0, + xref="x", + yref="y", + text=str(success_categoria), + showarrow=False, + font=dict(color="#45cc6e", size=14), + xanchor="left", + yanchor="middle", + ), + dict( + x=0, + y=0, + xref="x", + yref="y", + text=str(failed_categoria), + showarrow=False, + font=dict(color="#e77676", size=14), + xanchor="right", + yanchor="middle", + ), + ], + ) + fig_section.add_annotation( + x=failed_categoria, + y=0.3, + text="|", + showarrow=False, + font=dict(size=20), + xanchor="center", + yanchor="middle", + ) + + graph_div_section = html.Div( + dcc.Graph( + figure=fig_section, + config={"staticPlot": True}, + className="info-bar-child", + ), + className="graph-section-req", + ) + direct_internal_items_idgrupocontrol = [] + + for idgrupocontrol in specific_data[section_3].unique(): + specific_data2 = specific_data[ + specific_data[section_3] == idgrupocontrol + ] + findings_counts_idgrupocontrol = ( + specific_data2.groupby([section_3, "STATUS"]) + .size() + .unstack(fill_value=0) + ) + success_idgrupocontrol = findings_counts_idgrupocontrol.loc[ + idgrupocontrol + ].get(pass_emoji, 0) + failed_idgrupocontrol = findings_counts_idgrupocontrol.loc[ + idgrupocontrol + ].get(fail_emoji, 0) + + fig_idgrupocontrol = go.Figure( + [ + go.Bar( + name="Failed", + x=[failed_idgrupocontrol], + y=[""], + orientation="h", + marker=dict(color="#e77676"), + width=[0.8], + ), + go.Bar( + name="Success", + x=[success_idgrupocontrol], + y=[""], + orientation="h", + marker=dict(color="#45cc6e"), + width=[0.8], + ), + ] + ) + fig_idgrupocontrol.update_layout( + barmode="stack", + margin=dict(l=10, r=10, t=10, b=10), + paper_bgcolor="rgba(0,0,0,0)", + plot_bgcolor="rgba(0,0,0,0)", + showlegend=False, + width=350, + height=30, + xaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + yaxis=dict(showticklabels=False, showgrid=False, zeroline=False), + annotations=[ + dict( + x=success_idgrupocontrol + failed_idgrupocontrol, + y=0, + xref="x", + yref="y", + text=str(success_idgrupocontrol), + showarrow=False, + font=dict(color="#45cc6e", size=14), + xanchor="left", + yanchor="middle", + ), + dict( + x=0, + y=0, + xref="x", + yref="y", + text=str(failed_idgrupocontrol), + showarrow=False, + font=dict(color="#e77676", size=14), + xanchor="right", + yanchor="middle", + ), + ], + ) + fig_idgrupocontrol.add_annotation( + x=failed_idgrupocontrol, + y=0.3, + text="|", + showarrow=False, + font=dict(size=20), + xanchor="center", + yanchor="middle", + ) + + graph_div_idgrupocontrol = html.Div( + dcc.Graph( + figure=fig_idgrupocontrol, + config={"staticPlot": True}, + className="info-bar-child", + ), + className="graph-section-req", + ) + + data_table = dash_table.DataTable( + data=specific_data2.to_dict("records"), + columns=[ + {"name": i, "id": i} + for i in [ + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ], + style_table={"overflowX": "auto"}, + style_as_list_view=True, + style_cell={"textAlign": "left", "padding": "5px"}, + ) + + internal_accordion_item_2 = dbc.AccordionItem( + title=idgrupocontrol, + children=[ + graph_div_idgrupocontrol, + html.Div([data_table], className="inner-accordion-content"), + ], + ) + direct_internal_items_idgrupocontrol.append( + html.Div( + [ + graph_div_idgrupocontrol, + dbc.Accordion( + [internal_accordion_item_2], + start_collapsed=True, + flush=True, + ), + ], + className="accordion-inner--child", + ) + ) + + internal_accordion_item = dbc.AccordionItem( + title=categoria, + children=direct_internal_items_idgrupocontrol, + ) + internal_section_container = html.Div( + [ + graph_div_section, + dbc.Accordion( + [internal_accordion_item], start_collapsed=True, flush=True + ), + ], + className="accordion-inner--child", + ) + direct_internal_items.append(internal_section_container) + + accordion_item = dbc.AccordionItem(title=marco, children=direct_internal_items) + section_container = html.Div( + [ + graph_div, + dbc.Accordion([accordion_item], start_collapsed=True, flush=True), + ], + className="accordion-inner", + ) + section_containers.append(section_container) + + return html.Div(section_containers, className="compliance-data-layout") + + # This function extracts and compares up to two numeric values, ensuring correct sorting for version-like strings. def extract_numeric_values(value): numbers = re.findall(r"\d+", str(value)) - if len(numbers) >= 2: + if len(numbers) == 3: + return int(numbers[0]), int(numbers[1]), int(numbers[2]) + elif len(numbers) == 2: return int(numbers[0]), int(numbers[1]) elif len(numbers) == 1: - return int(numbers[0]), 0 + return int(numbers[0]) return 0, 0 diff --git a/dashboard/compliance/aws_well_architected_framework_reliability_pillar_aws.py b/dashboard/compliance/aws_well_architected_framework_reliability_pillar_aws.py index 02fae31d81..d2c3272352 100644 --- a/dashboard/compliance/aws_well_architected_framework_reliability_pillar_aws.py +++ b/dashboard/compliance/aws_well_architected_framework_reliability_pillar_aws.py @@ -1,6 +1,6 @@ import warnings -from dashboard.common_methods import get_section_containers_format2 +from dashboard.common_methods import get_section_containers_3_levels warnings.filterwarnings("ignore") @@ -10,6 +10,7 @@ def get_table(data): [ "REQUIREMENTS_ATTRIBUTES_NAME", "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", "CHECKID", "STATUS", "REGION", @@ -17,6 +18,10 @@ def get_table(data): "RESOURCEID", ] ] - return get_section_containers_format2( - aux, "REQUIREMENTS_ATTRIBUTES_NAME", "REQUIREMENTS_ATTRIBUTES_SECTION" + + return get_section_containers_3_levels( + aux, + "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", + "REQUIREMENTS_ATTRIBUTES_NAME", ) diff --git a/dashboard/compliance/aws_well_architected_framework_security_pillar_aws.py b/dashboard/compliance/aws_well_architected_framework_security_pillar_aws.py index cfa7ecab40..d2c3272352 100644 --- a/dashboard/compliance/aws_well_architected_framework_security_pillar_aws.py +++ b/dashboard/compliance/aws_well_architected_framework_security_pillar_aws.py @@ -1,6 +1,6 @@ import warnings -from dashboard.common_methods import get_section_containers_format2 +from dashboard.common_methods import get_section_containers_3_levels warnings.filterwarnings("ignore") @@ -10,6 +10,7 @@ def get_table(data): [ "REQUIREMENTS_ATTRIBUTES_NAME", "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", "CHECKID", "STATUS", "REGION", @@ -18,6 +19,9 @@ def get_table(data): ] ] - return get_section_containers_format2( - aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ATTRIBUTES_NAME" + return get_section_containers_3_levels( + aux, + "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", + "REQUIREMENTS_ATTRIBUTES_NAME", ) diff --git a/dashboard/compliance/kisa_isms_p_2023_aws.py b/dashboard/compliance/kisa_isms_p_2023_aws.py index 1d079d46af..66643dab04 100644 --- a/dashboard/compliance/kisa_isms_p_2023_aws.py +++ b/dashboard/compliance/kisa_isms_p_2023_aws.py @@ -1,6 +1,6 @@ import warnings -from dashboard.common_methods import get_section_containers_kisa_ismsp +from dashboard.common_methods import get_section_containers_3_levels warnings.filterwarnings("ignore") @@ -8,7 +8,7 @@ warnings.filterwarnings("ignore") def get_table(data): aux = data[ [ - "REQUIREMENTS_ID", + "REQUIREMENTS_ATTRIBUTES_DOMAIN", "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", "REQUIREMENTS_ATTRIBUTES_SECTION", # "REQUIREMENTS_DESCRIPTION", @@ -20,6 +20,9 @@ def get_table(data): ] ].copy() - return get_section_containers_kisa_ismsp( - aux, "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", "REQUIREMENTS_ATTRIBUTES_SECTION" + return get_section_containers_3_levels( + aux, + "REQUIREMENTS_ATTRIBUTES_DOMAIN", + "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", + "REQUIREMENTS_ATTRIBUTES_SECTION", ) diff --git a/dashboard/compliance/kisa_isms_p_2023_korean_aws.py b/dashboard/compliance/kisa_isms_p_2023_korean_aws.py index 1d079d46af..66643dab04 100644 --- a/dashboard/compliance/kisa_isms_p_2023_korean_aws.py +++ b/dashboard/compliance/kisa_isms_p_2023_korean_aws.py @@ -1,6 +1,6 @@ import warnings -from dashboard.common_methods import get_section_containers_kisa_ismsp +from dashboard.common_methods import get_section_containers_3_levels warnings.filterwarnings("ignore") @@ -8,7 +8,7 @@ warnings.filterwarnings("ignore") def get_table(data): aux = data[ [ - "REQUIREMENTS_ID", + "REQUIREMENTS_ATTRIBUTES_DOMAIN", "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", "REQUIREMENTS_ATTRIBUTES_SECTION", # "REQUIREMENTS_DESCRIPTION", @@ -20,6 +20,9 @@ def get_table(data): ] ].copy() - return get_section_containers_kisa_ismsp( - aux, "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", "REQUIREMENTS_ATTRIBUTES_SECTION" + return get_section_containers_3_levels( + aux, + "REQUIREMENTS_ATTRIBUTES_DOMAIN", + "REQUIREMENTS_ATTRIBUTES_SUBDOMAIN", + "REQUIREMENTS_ATTRIBUTES_SECTION", ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 4d3312ef81..93d065e206 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,8 +38,9 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add the correct values for logger.info inside iam service [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526). - Update S3 bucket naming validation to accept dots [(#7545)](https://github.com/prowler-cloud/prowler/pull/7545). - Handle new FlowLog model properties in Azure [(#7546)](https://github.com/prowler-cloud/prowler/pull/7546). +- Improve compliance and dashboard [(#7596)](https://github.com/prowler-cloud/prowler/pull/7596) +- Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) - Remove first empty line in HTML output [(#7606)](https://github.com/prowler-cloud/prowler/pull/7606) -- Remove invalid parameter `create_file_descriptor` in NHN provider [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) --- diff --git a/prowler/compliance/aws/kisa_isms_p_2023_aws.json b/prowler/compliance/aws/kisa_isms_p_2023_aws.json index f4f9736e54..28d1fc4406 100644 --- a/prowler/compliance/aws/kisa_isms_p_2023_aws.json +++ b/prowler/compliance/aws/kisa_isms_p_2023_aws.json @@ -12,7 +12,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.1 Executive Participation", "AuditChecklist": [ "Is there documentation outlining the responsibilities and roles of executives to ensure their participation in the establishment and operation of the information protection and personal information protection management system?", @@ -41,7 +41,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.2 Designation of Chief Officers", "AuditChecklist": [ "Has the CEO officially designated a chief officer responsible for overseeing information protection and personal information protection?", @@ -77,7 +77,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.3 Organization Structure", "AuditChecklist": [ "Has the organization established and operated a working group with expertise to support the work of the CISO and CPO and systematically implement the organization's information protection and personal information protection activities?", @@ -112,7 +112,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.4 Scope Setting", "AuditChecklist": [ "Has the organization set the scope of the management system to include key assets that may affect core services and personal information processing?", @@ -145,7 +145,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.5 Policy Establishment", "AuditChecklist": [ "Has the organization established a top-level information protection and personal information protection policy that serves as the foundation for all information protection and personal information protection activities?", @@ -180,7 +180,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.1. Management System", + "Subdomain": "1.1 Management System", "Section": "1.1.6 Resource Allocation", "AuditChecklist": [ "Has the organization secured personnel with expertise in the fields of information protection and personal information protection?", @@ -216,7 +216,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.2. Risk Management", + "Subdomain": "1.2 Risk Management", "Section": "1.2.1 Identification of Information Assets", "AuditChecklist": [ "Has the organization established classification criteria for information assets and identified all assets within the scope of the information protection and personal information protection management system, maintaining them in a list?", @@ -249,7 +249,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.2. Risk Management", + "Subdomain": "1.2 Risk Management", "Section": "1.2.2 Status and Flow Analysis", "AuditChecklist": [ "Has the organization identified and documented the status and workflows of information services across all areas of the management system?", @@ -279,7 +279,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.2. Risk Management", + "Subdomain": "1.2 Risk Management", "Section": "1.2.3 Risk Assessment", "AuditChecklist": [ "Has the organization defined methods for identifying and assessing risks that could arise from various aspects, depending on the characteristics of the organization or service?", @@ -322,7 +322,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.2. Risk Management", + "Subdomain": "1.2 Risk Management", "Section": "1.2.4 Selection of Protective Measures", "AuditChecklist": [ "Has the organization developed risk treatment strategies (e.g., risk reduction, avoidance, transfer, acceptance) and selected protective measures to address the identified risks?", @@ -352,7 +352,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.3. Operation of the Management System", + "Subdomain": "1.3 Operation of the Management System", "Section": "1.3.1 Implementation of Protective Measures", "AuditChecklist": [ "Are the protective measures effectively implemented according to the implementation plan, and are the implementation results reported to management to verify their accuracy and effectiveness?", @@ -384,7 +384,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.3. Operation of the Management System", + "Subdomain": "1.3 Operation of the Management System", "Section": "1.3.2 Sharing of Protective Measures", "AuditChecklist": [ "Has the organization clearly identified the departments and personnel responsible for the operation or implementation of the protective measures?", @@ -409,7 +409,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.3. Operation of the Management System", + "Subdomain": "1.3 Operation of the Management System", "Section": "1.3.3 Operation Status Management", "AuditChecklist": [ "Are information protection and personal information protection activities that need to be performed periodically or continuously for the operation of the management system documented and managed?", @@ -439,7 +439,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.4. Inspection and Improvement of the Management System", + "Subdomain": "1.4 Inspection and Improvement of the Management System", "Section": "1.4.1 Review of Legal Requirements Compliance", "AuditChecklist": [ "Is the organization regularly identifying and maintaining up-to-date legal requirements related to information protection and personal information protection?", @@ -477,7 +477,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.4. Inspection and Improvement of the Management System", + "Subdomain": "1.4 Inspection and Improvement of the Management System", "Section": "1.4.2 Management System Audit", "AuditChecklist": [ "Has the organization established a management system audit plan that includes the criteria, scope, frequency, and qualifications for audit personnel to audit the management system's effectiveness in accordance with legal requirements and established policies?", @@ -508,7 +508,7 @@ "Attributes": [ { "Domain": "1. Establishment and Operation of the Management System", - "Subdomain": "1.4. Management System Inspection and Improvement", + "Subdomain": "1.4 Inspection and Improvement of the Management System", "Section": "1.4.3 Management System Improvement", "AuditChecklist": [ "Are the root causes of the issues identified during legal compliance reviews and management system inspections analyzed, and are preventive and improvement measures established and implemented?", @@ -541,7 +541,7 @@ "Attributes": [ { "Domain": "2. Control Measures Requirements", - "Subdomain": "2.1. Policies, Organization, and Asset Management", + "Subdomain": "2.1 Policy, Organization, Asset Management", "Section": "2.1.1 Policy Maintenance", "AuditChecklist": [ "Has the organization established and implemented a procedure for regularly reviewing the validity of information protection and personal information protection policies and implementation documents?", @@ -577,7 +577,7 @@ "Attributes": [ { "Domain": "2. Control Measures Requirements", - "Subdomain": "2.1. Policies, Organization, and Asset Management", + "Subdomain": "2.1 Policy, Organization, Asset Management", "Section": "2.1.2 Organization Maintenance", "AuditChecklist": [ "Are the roles and responsibilities of those responsible for and involved in information protection and personal information protection clearly defined?", @@ -624,8 +624,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.1. Policy, Organization, Asset Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.1 Policy, Organization, Asset Management", "Section": "2.1.3 Management of Information Assets", "AuditChecklist": [ "Are handling procedures (creation, introduction, storage, use, disposal) and protection measures defined and implemented according to the security classification of information assets?", @@ -657,8 +657,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.2. Personnel Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.1 Designation and Management of Key Personnel", "AuditChecklist": [ "Are the criteria for key duties, such as handling personal information and important information or accessing key systems, clearly defined?", @@ -693,8 +693,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.2. Personnel Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.2 Separation of Duties", "AuditChecklist": [ "Are criteria for the separation of duties established and applied to prevent potential harm from the misuse or abuse of authority?", @@ -720,8 +720,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.2. Human Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.3 Security Pledge", "AuditChecklist": [ "When hiring new personnel, is there a signed security and personal information protection agreement that specifies their responsibilities?", @@ -750,8 +750,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.2. Human Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.4 Awareness and Training", "AuditChecklist": [ "Is an annual training plan approved by management, detailing the timing, duration, target audience, content, and method of information protection and personal information protection training?", @@ -788,8 +788,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.2. Human Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.5 Management of Resignation and Job Changes", "AuditChecklist": [ "Are personnel changes (e.g., resignation, job changes, department transfers, leave of absence) shared among HR, information protection, personal information protection, and IT system operations departments?", @@ -820,8 +820,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.2. Human Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.2 Human Security", "Section": "2.2.6 Actions in Case of Security Violations", "AuditChecklist": [ "Has the organization established disciplinary measures for employees and relevant external parties in case of violations of information protection and personal information protection responsibilities and obligations under laws, regulations, and internal policies?", @@ -847,8 +847,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.3. External Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.3 External Security", "Section": "2.3.1 Management of External Parties", "AuditChecklist": [ "Has the organization identified the status of outsourcing and the use of external facilities and services within the scope of the management system?", @@ -878,8 +878,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.3. External Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.3 External Security", "Section": "2.3.2 Security in Contracts with External Parties", "AuditChecklist": [ "When selecting external services or outsourcing vendors related to the handling of important information and personal information, does the organization follow procedures to consider the vendors' capabilities in information protection and personal information protection?", @@ -910,8 +910,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.3. External Party Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.3 External Security", "Section": "2.3.3 External Party Security Implementation Management", "AuditChecklist": [ "Are periodic inspections or audits conducted to ensure external parties comply with information protection and personal information protection requirements specified in contracts, agreements, and internal policies?", @@ -945,8 +945,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.3. External Party Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.3 External Security", "Section": "2.3.4 Security for External Party Contract Changes and Expiry", "AuditChecklist": [ "Has the organization established and implemented security measures to ensure the return of information assets, deletion of information system access accounts, and the acquisition of confidentiality agreements in accordance with official procedures when an external party contract expires, a task is completed, or there is a personnel change?", @@ -977,8 +977,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.1 Designation of Protected Zones", "AuditChecklist": [ "Has the organization established criteria for designating physical protection zones such as controlled areas, restricted areas, and reception areas to protect personal and sensitive information, documents, storage media, key facilities, and systems from physical and environmental threats?", @@ -1008,8 +1008,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.2 Access Control", "AuditChecklist": [ "Is access to protected areas controlled so that only authorized personnel are allowed to enter according to access procedures?", @@ -1040,8 +1040,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.3 Information System Protection", "AuditChecklist": [ "Are information systems placed in separated locations based on their importance, usage, and characteristics?", @@ -1068,8 +1068,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.4 Operation of Protective Facilities", "AuditChecklist": [ "Are necessary facilities established and operational procedures set up based on the importance and characteristics of each protected area to prevent disasters such as fire, flood, and power failure caused by human error or natural disasters?", @@ -1100,8 +1100,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.5 Operations in Secure Zones", "AuditChecklist": [ "When operations within secure zones, such as the introduction and maintenance of information systems, are required, are formal procedures for application and execution of such operations established and implemented?", @@ -1127,8 +1127,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.6 Device Control for Inbound and Outbound", "AuditChecklist": [ "Are control procedures established and implemented to prevent security incidents such as information leakage and malware infection when information systems, mobile devices, storage media, etc., are brought into or taken out of secure zones?", @@ -1157,8 +1157,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.4. Physical Security", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.4 Physical Security", "Section": "2.4.7 Work Environment Security", "AuditChecklist": [ "Are protection measures established and implemented for shared facilities and office equipment such as document storage, shared PCs, multifunction printers, file servers, etc.?", @@ -1215,8 +1215,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.5. Authentication and Access Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.1 User Account Management", "AuditChecklist": [ "Has the organization established and implemented formal procedures for registering, changing, and deleting user accounts and access rights to information systems, personal information, and critical information?", @@ -1248,8 +1248,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.5. Authentication and Access Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.2 User Identification", "AuditChecklist": [ "Are unique identifiers assigned to users and personal information handlers in information systems and personal information processing systems, and is the use of easily guessable identifiers restricted?", @@ -1309,8 +1309,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.5. Authentication and Authorization Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.3 User Authentication", "AuditChecklist": [ "Is access to information systems and personal information processing systems controlled through secure user authentication procedures, login attempt limitations, and warnings for illegal login attempts?", @@ -1354,8 +1354,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.5. Authentication and Authorization Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.4 Password Management", "AuditChecklist": [ "Are procedures for managing and creating secure user passwords for information systems established and implemented?", @@ -1397,8 +1397,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.5. Authentication and Privilege Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.5 Management of Special Accounts and Privileges", "AuditChecklist": [ "Is there a formal privilege request and approval process established and implemented to ensure that special privileges, such as administrative privileges, are only granted to a minimal number of people?", @@ -1445,8 +1445,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.5. Authentication and Privilege Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.5 Authentication and Access Management", "Section": "2.5.6 Review of Access Rights", "AuditChecklist": [ "Are the histories of account and access right creation, registration, granting, use, modification, and deletion for information systems, personal information, and important information being recorded?", @@ -1590,8 +1590,8 @@ ], "Attributes": [ { - "Domain": "2. Control Measures", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.1 Network Access", "AuditChecklist": [ "Has the organization identified all access paths to its network and ensured that internal networks are controlled so that only authorized users can access them according to the access control policy?", @@ -1651,8 +1651,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.2 Access to Information Systems", "AuditChecklist": [ "Have users, access locations, and access means allowed to access operating systems (OS) of information systems such as servers, network systems, and security systems been defined and controlled?", @@ -1687,8 +1687,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.3 Access to Applications", "AuditChecklist": [ "Are access rights to applications granted differentially based on the user's tasks to control access to sensitive information?", @@ -1769,8 +1769,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.4 Database Access", "AuditChecklist": [ "Are you identifying the information stored and managed in the database, such as the table list?", @@ -1804,8 +1804,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.5 Wireless Network Access", "AuditChecklist": [ "When using a wireless network for business purposes, are you establishing and implementing protection measures such as authentication and encryption of transmitted and received data to ensure the security of the wireless AP and network segment?", @@ -1864,8 +1864,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.6 Remote Access Control", "AuditChecklist": [ "Is remote operation of information systems through external networks such as the internet prohibited in principle, and are compensatory measures in place if allowed for unavoidable reasons such as incident response?", @@ -1922,8 +1922,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.6. Access Control", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.6 Access Control", "Section": "2.6.7 Internet Access Control", "AuditChecklist": [ "Is there an established and implemented policy to control internet access for work PCs used for key duties and personal information handling terminals?", @@ -2025,8 +2025,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.7. Application of Encryption", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.7 Application of Encryption", "Section": "2.7.1 Application of Encryption Policy", "AuditChecklist": [ "Has an encryption policy been established that includes encryption targets, encryption strength, and encryption usage in consideration of legal requirements for the protection of personal and important information?", @@ -2069,8 +2069,8 @@ ], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.7. Application of Encryption", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.7 Application of Encryption", "Section": "2.7.2 Cryptographic Key Management", "AuditChecklist": [ "Are procedures for the generation, use, storage, distribution, modification, recovery, and destruction of cryptographic keys established and implemented?", @@ -2116,8 +2116,8 @@ ], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.8. Security for Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.1 Definition of Security Requirements", "AuditChecklist": [ "When introducing, developing, or modifying an information system, are procedures for reviewing the validity of information protection and personal information protection aspects and for acquisition established and implemented?", @@ -2167,8 +2167,8 @@ ], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.8. Security for Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.2 Review and Testing of Security Requirements", "AuditChecklist": [ "When introducing, developing, or modifying an information system, are tests conducted to verify whether the security requirements defined during the analysis and design stages have been effectively applied?", @@ -2208,8 +2208,8 @@ ], "Attributes": [ { - "Domain": "2. Security Requirements for Protection Measures", - "Subdomain": "2.8. Security for Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.3 Separation of Test and Production Environments", "AuditChecklist": [ "Are development and test systems separated from the production system?", @@ -2237,8 +2237,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.8. Security in Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.4 Test Data Security", "AuditChecklist": [ "Is the use of actual operational data restricted during the development and testing of information systems?", @@ -2269,8 +2269,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.8. Security in Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.5 Source Program Management", "AuditChecklist": [ "Have procedures been established and implemented to control access to source programs by unauthorized persons?", @@ -2297,8 +2297,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.8. Security in Information System Introduction and Development", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.8 Security in Information System Introduction and Development", "Section": "2.8.6 Transition to Operational Environment", "AuditChecklist": [ "Have control procedures been established and implemented to safely transition newly introduced, developed, or modified systems to the operational environment?", @@ -2341,8 +2341,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.9. System and Service Operations Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.1 Change Management", "AuditChecklist": [ "Have procedures been established and implemented for changes to assets related to information systems (hardware, operating systems, commercial software packages, etc.)?", @@ -2409,8 +2409,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.9. System and Service Operations Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.2 Performance and Fault Management", "AuditChecklist": [ "Have procedures been established and implemented to continuously monitor performance and capacity to ensure the availability of information systems?", @@ -2480,8 +2480,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.9. System and Service Operation Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.3 Backup and Recovery Management", "AuditChecklist": [ "Have backup and recovery procedures been established and implemented, including targets, frequency, methods, and procedures?", @@ -2595,8 +2595,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.9. System and Service Operation Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.4 Log and Access Record Management", "AuditChecklist": [ "Has the organization established log management procedures for information systems such as servers, applications, security systems, and network systems, and is it generating and storing the necessary logs accordingly?", @@ -2658,8 +2658,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Control Requirements", - "Subdomain": "2.9. System and Service Operation Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.5 Log and Access Record Inspection", "AuditChecklist": [ "Are there established log review and monitoring procedures, including the frequency, targets, and methods for detecting errors, misuse (unauthorized access, excessive queries, etc.), fraud, and other anomalies in the information system?", @@ -2693,8 +2693,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Control Requirements", - "Subdomain": "2.9. System and Service Operation Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.6 Time Synchronization", "AuditChecklist": [ "Is the system time synchronized with the standard time?", @@ -2719,8 +2719,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Control Requirements", - "Subdomain": "2.9. System and Service Operation Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.9 System and Service Operation Management", "Section": "2.9.7 Reuse and Disposal of Information Assets", "AuditChecklist": [ "Are secure reuse and disposal procedures for information assets established and implemented?", @@ -2831,8 +2831,8 @@ ], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.1 Security System Operation", "AuditChecklist": [ "Has the organization established and implemented operational procedures for the security systems in use?", @@ -2872,8 +2872,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protective Measure Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.2 Cloud Security", "AuditChecklist": [ "Is the responsibility and role for information protection and personal information protection clearly defined with the cloud service provider, and is it reflected in contracts (such as SLA)?", @@ -2984,8 +2984,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measure Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.3 Public Server Security", "AuditChecklist": [ "Are protective measures established and implemented for the operation of public servers?", @@ -3014,8 +3014,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.4 Security for Electronic Transactions and FinTech", "AuditChecklist": [ "Are protection measures established and implemented to ensure the safety and reliability of transactions when providing electronic transaction and FinTech services?", @@ -3059,8 +3059,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.5 Secure Information Transmission", "AuditChecklist": [ "Has a secure transmission policy been established when transmitting personal and critical information to external organizations?", @@ -3093,8 +3093,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measure Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.6 Security for Business Devices", "AuditChecklist": [ "Are security control policies, such as device authentication, approval, access scope, and security settings, established and implemented for devices used for business purposes, such as PCs, laptops, virtual PCs, and tablets?", @@ -3129,8 +3129,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.7 Management of Removable Media", "AuditChecklist": [ "Are policies and procedures established and implemented for handling (use), storage, disposal, and reuse of removable media such as external hard drives, USB memory, and CDs?", @@ -3179,8 +3179,8 @@ ], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.8 Patch Management", "AuditChecklist": [ "Are patch management policies and procedures for operating systems (OS) and software established and implemented according to the characteristics and importance of each asset, such as servers, network systems, security systems, and PCs?", @@ -3213,8 +3213,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Security Control Requirements", - "Subdomain": "2.10. System and Service Security Management", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.10 System and Service Security Management", "Section": "2.10.9 Malware Control", "AuditChecklist": [ "Are protection measures established and implemented to protect information systems and business terminals from malware such as viruses, worms, Trojans, and ransomware?", @@ -3248,8 +3248,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.11. Incident Prevention and Response", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.11 Incident Prevention and Response", "Section": "2.11.1 Establishment of Incident Prevention and Response System", "AuditChecklist": [ "Has the organization established procedures and systems to prevent security breaches and personal information leaks and to respond quickly and effectively when incidents occur?", @@ -3307,8 +3307,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measures Requirements", - "Subdomain": "2.11. Incident Prevention and Response", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.11 Incident Prevention and Response", "Section": "2.11.2 Vulnerability Inspection and Remediation", "AuditChecklist": [ "Has the organization established and implemented procedures for conducting regular vulnerability inspections of information systems?", @@ -3371,8 +3371,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.11. Incident Prevention and Response", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.11 Incident Prevention and Response", "Section": "2.11.3 Abnormal Behavior Analysis and Monitoring", "AuditChecklist": [ "Is the organization collecting, analyzing, and monitoring network traffic, data flows, and event logs from major information systems, applications, networks, and security systems to detect abnormal behaviors such as intrusion attempts, personal information leakage attempts, or fraudulent activities?", @@ -3403,8 +3403,8 @@ ], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.11. Incident Prevention and Response", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.11 Incident Prevention and Response", "Section": "2.11.4 Incident Response Training and Improvement", "AuditChecklist": [ "Has the organization established a simulation training plan for responding to security incidents and personal information leakage incidents, and are such training exercises conducted at least once a year?", @@ -3431,8 +3431,8 @@ "Checks": [], "Attributes": [ { - "Domain": "2. Protection Measures Requirements", - "Subdomain": "2.11. Incident Prevention and Response", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.11 Incident Prevention and Response", "Section": "2.11.5 Incident Response and Recovery", "AuditChecklist": [ "When signs of or actual incidents of security breaches or personal information leakage are detected, is the organization responding and reporting promptly according to the defined incident response procedures?", @@ -3501,8 +3501,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measure Requirements", - "Subdomain": "2.12. Disaster Recovery", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.12 Disaster Recovery", "Section": "2.12.1 Safety Measures for Disaster Preparedness", "AuditChecklist": [ "Has the organization identified IT disaster types that could threaten the continuity of core services (businesses) and analyzed the expected scale of damage and impact on operations to identify core IT services (businesses) and systems?", @@ -3570,8 +3570,8 @@ ], "Attributes": [ { - "Domain": "2. Protective Measure Requirements", - "Subdomain": "2.12. Disaster Recovery", + "Domain": "2. Control Measures Requirements", + "Subdomain": "2.12 Disaster Recovery", "Section": "2.12.2 Disaster Recovery Testing and Improvement", "AuditChecklist": [ "Has the organization established and implemented disaster recovery test plans to evaluate the effectiveness of the established IT disaster recovery system?", @@ -3599,7 +3599,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.1. Protection Measures during Personal Information Collection", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.1 Collection and Use of Personal Information", "AuditChecklist": [ "When collecting personal information, is it collected in accordance with lawful requirements such as obtaining the data subject’s consent, complying with legal obligations, or concluding and fulfilling contracts?", @@ -3645,7 +3645,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.1. Protection Measures during Personal Information Collection", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.2 Restrictions on the Collection of Personal Information", "AuditChecklist": [ "When collecting personal information, is only the minimum amount of information necessary for the intended purpose being collected?", @@ -3678,7 +3678,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.1. Protection Measures during Personal Information Collection", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.3 Restrictions on the Processing of Resident Registration Numbers", "AuditChecklist": [ "Are resident registration numbers only processed when there is a clear legal basis?", @@ -3713,8 +3713,8 @@ "Checks": [], "Attributes": [ { - "Domain": "3. Personal Information Processing Requirements", - "Subdomain": "3.1. Protection Measures for Personal Information Collection", + "Domain": "3. Requirements for Each Stage of Personal Information Processing", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.4 Restriction on Processing of Sensitive and Unique Identifying Information", "AuditChecklist": [ "Is sensitive information processed only with the separate consent of the data subject or when legally required?", @@ -3744,8 +3744,8 @@ "Checks": [], "Attributes": [ { - "Domain": "3. Personal Information Processing Requirements", - "Subdomain": "3.1. Protection Measures for Personal Information Collection", + "Domain": "3. Requirements for Each Stage of Personal Information Processing", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.5 Indirect Collection of Personal Information", "AuditChecklist": [ "When receiving personal information from a third party, is it clearly stated in the contract that the responsibility for obtaining consent for the collection of personal information lies with the party providing the information?", @@ -3779,8 +3779,8 @@ "Checks": [], "Attributes": [ { - "Domain": "3. Personal Information Processing Requirements", - "Subdomain": "3.1. Protection Measures for Personal Information Collection", + "Domain": "3. Requirements for Each Stage of Personal Information Processing", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.6 Installation and Operation of Video Information Processing Devices", "AuditChecklist": [ "When installing and operating fixed video information processing devices in public places, is it reviewed whether the installation meets legal requirements?", @@ -3819,7 +3819,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.1. Protection Measures When Collecting Personal Information", + "Subdomain": "3.1 Protection Measures for Personal Information Collection", "Section": "3.1.7 Collection and Use of Personal Information for Marketing Purposes", "AuditChecklist": [ "When obtaining consent from data subjects to process personal information for the purpose of promoting or recommending goods or services, is the data subject clearly informed, and is separate consent obtained?", @@ -3861,7 +3861,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.2. Protection Measures When Retaining and Using Personal Information", + "Subdomain": "3.2 Protection Measures When Retaining and Using Personal Information", "Section": "3.2.1 Management of Personal Information Status", "AuditChecklist": [ "Is the status of collected and retained personal information, including the items, volume, purpose and method of processing, and retention period, regularly managed?", @@ -3904,7 +3904,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information", + "Subdomain": "3.2 Protection Measures When Retaining and Using Personal Information", "Section": "3.2.2 Personal Information Quality Assurance", "AuditChecklist": [ "Are procedures and methods in place to maintain personal information in an accurate and up-to-date state?", @@ -3932,7 +3932,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information", + "Subdomain": "3.2 Protection Measures When Retaining and Using Personal Information", "Section": "3.2.3 Protection of User Device Access", "AuditChecklist": [ "When accessing information stored on the user's mobile device or functions installed on the device, are users clearly informed and their consent obtained?", @@ -3963,7 +3963,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information", + "Subdomain": "3.2 Protection Measures When Retaining and Using Personal Information", "Section": "3.2.4 Use and Provision of Personal Information Beyond Purpose", "AuditChecklist": [ "Is personal information used or provided only within the scope of the purpose consented to by the data subject at the time of collection or as permitted by law?", @@ -4000,7 +4000,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information", + "Subdomain": "3.2 Protection Measures When Retaining and Using Personal Information", "Section": "3.2.5 Processing of Pseudonymized Information", "AuditChecklist": [ "When processing pseudonymized information, are procedures established for purpose limitation, pseudonymization methods and standards, adequacy review, prohibition of re-identification, and actions in case of re-identification?", @@ -4035,7 +4035,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.3. Protective Measures When Providing Personal Information", + "Subdomain": "3.3 Protection Measures When Providing Personal Information", "Section": "3.3.1 Provision of Personal Information to Third Parties", "AuditChecklist": [ "When providing personal information to third parties, are legal requirements such as consent from the data subject or compliance with legal obligations clearly identified and followed?", @@ -4074,7 +4074,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.3. Protective Measures When Providing Personal Information", + "Subdomain": "3.3 Protection Measures When Providing Personal Information", "Section": "3.3.2 Outsourcing of Personal Information Processing", "AuditChecklist": [ "When outsourcing personal information processing tasks (including sub-outsourcing) to third parties, are the details of the outsourced tasks and the trustees regularly updated and disclosed on the website?", @@ -4106,7 +4106,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.3. Protective Measures When Providing Personal Information", + "Subdomain": "3.3 Protection Measures When Providing Personal Information", "Section": "3.3.3 Transfer of Personal Information Due to Business Transfers", "AuditChecklist": [ "When transferring personal information to another party due to the transfer or merger of all or part of the business, are the necessary matters communicated to the data subjects in advance?", @@ -4137,7 +4137,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.3. Protection Measures When Providing Personal Information", + "Subdomain": "3.3 Protection Measures When Providing Personal Information", "Section": "3.3.4 Transfer of Personal Information Abroad", "AuditChecklist": [ "When transferring personal information abroad, has the data subject been fully informed of all notification requirements and obtained separate consent, or complied with certification or recognition, as required by law?", @@ -4171,7 +4171,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.4. Protection Measures When Destroying Personal Information", + "Subdomain": "3.4 Protection Measures When Destroying Personal Information", "Section": "3.4.1 Destruction of Personal Information", "AuditChecklist": [ "Has an internal policy been established regarding the retention period and destruction of personal information?", @@ -4205,7 +4205,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.4. Protection Measures When Destroying Personal Information", + "Subdomain": "3.4 Protection Measures When Destroying Personal Information", "Section": "3.4.2 Measures When Retaining Personal Information After Purpose Is Achieved", "AuditChecklist": [ "When personal information is retained beyond the retention period or after the processing purpose has been achieved, in accordance with relevant laws, is it limited to the minimum necessary period and only the minimum necessary information?", @@ -4238,7 +4238,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.5. Protection of Data Subject's Rights", + "Subdomain": "3.5 Protection of Data Subject's Rights", "Section": "3.5.1 Disclosure of Privacy Policy", "AuditChecklist": [ "Is the privacy policy written in clear and easy-to-understand language, covering all the contents required by law?", @@ -4270,7 +4270,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.5. Protection of Data Subject's Rights", + "Subdomain": "3.5 Protection of Data Subject's Rights", "Section": "3.5.2 Guaranteeing Data Subject's Rights", "AuditChecklist": [ "Are procedures in place to ensure that data subjects or their representatives can exercise their rights (hereinafter referred to as 'Requests for Access, etc.') to access, rectify, delete, or suspend the processing of their personal information in a way that is not more difficult than the process used for collecting it?", @@ -4309,7 +4309,7 @@ "Attributes": [ { "Domain": "3. Requirements for Each Stage of Personal Information Processing", - "Subdomain": "3.5. Protection of Data Subject's Rights", + "Subdomain": "3.5 Protection of Data Subject's Rights", "Section": "3.5.3 Notification to Data Subjects", "AuditChecklist": [ "If the organization is legally obligated to do so, does it periodically notify data subjects of the use and provision of their personal information, or provide them with access to an information system where they can review such details?", diff --git a/prowler/compliance/azure/cis_2.0_azure.json b/prowler/compliance/azure/cis_2.0_azure.json index 6e914f5057..6a35609d3e 100644 --- a/prowler/compliance/azure/cis_2.0_azure.json +++ b/prowler/compliance/azure/cis_2.0_azure.json @@ -2607,7 +2607,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.", @@ -2629,7 +2629,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.", @@ -2651,7 +2651,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.", @@ -2673,7 +2673,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured.", @@ -2695,7 +2695,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days.", @@ -2717,7 +2717,7 @@ ], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Enable Network Watcher for Azure subscriptions.", @@ -2737,7 +2737,7 @@ "Checks": [], "Attributes": [ { - "Section": "6 Networking", + "Section": "6. Networking", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity.", @@ -2759,7 +2759,7 @@ ], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service.", @@ -2781,7 +2781,7 @@ ], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration. The features include: 1. Default Disk Encryption 2. Resilience, as Microsoft will managed the disk storage and move around if underlying hardware goes faulty 3. Reduction of costs over storage accounts", @@ -2803,7 +2803,7 @@ ], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE orServer Side Encryption (SSE).", @@ -2825,7 +2825,7 @@ ], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK).", @@ -2845,7 +2845,7 @@ "Checks": [], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "For added security, only install organization-approved extensions on VMs.", @@ -2867,7 +2867,7 @@ ], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Install endpoint protection for all virtual machines.", @@ -2887,7 +2887,7 @@ "Checks": [], "Attributes": [ { - "Section": "7 Virtual Machines", + "Section": "7. Virtual Machines", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "NOTE: This is a legacy recommendation. Managed Disks are encrypted by default and recommended for all new VM implementations. VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs", @@ -2909,7 +2909,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.", @@ -2931,7 +2931,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.", @@ -2953,7 +2953,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.", @@ -2975,7 +2975,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.", @@ -2997,7 +2997,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "The Key Vault contains object keys, secrets, and certificates. Accidental unavailability of a Key Vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the Key Vault objects. It is recommended the Key Vault be made recoverable by enabling the 'Do Not Purge' and 'Soft Delete' functions. This is in order to prevent loss of encrypted data, including storage accounts, SQL databases, and/or dependent services provided by Key Vault objects (Keys, Secrets, Certificates) etc. This may happen in the case of accidental deletion by a user or from disruptive activity by a malicious user. WARNING: A current limitation of the soft-delete feature across all Azure services is role assignments disappearing when Key Vault is deleted. All role assignments will need to be recreated after recovery.", @@ -3019,7 +3019,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "WARNING: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services.", @@ -3041,7 +3041,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys.", @@ -3063,7 +3063,7 @@ ], "Attributes": [ { - "Section": "8 Key Vault", + "Section": "8. Key Vault", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased.", @@ -3085,7 +3085,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented.", @@ -3107,7 +3107,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic.", @@ -3129,7 +3129,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS.", @@ -3151,7 +3151,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 2", "AssessmentStatus": "Automated", "Description": "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app.", @@ -3173,7 +3173,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords.", @@ -3195,7 +3195,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.", @@ -3217,7 +3217,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.", @@ -3239,7 +3239,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version.", @@ -3261,7 +3261,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to takeadvantage of security fixes, if any, and/or new functionalities of the newer version.", @@ -3283,7 +3283,7 @@ ], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions.", @@ -3303,7 +3303,7 @@ "Checks": [], "Attributes": [ { - "Section": "9 AppService", + "Section": "9. AppService", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions.", @@ -3323,7 +3323,7 @@ "Checks": [], "Attributes": [ { - "Section": "10 Miscellaneous", + "Section": "10. Miscellaneous", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion.", diff --git a/prowler/compliance/azure/cis_2.1_azure.json b/prowler/compliance/azure/cis_2.1_azure.json index 32336ba368..594b2ad851 100644 --- a/prowler/compliance/azure/cis_2.1_azure.json +++ b/prowler/compliance/azure/cis_2.1_azure.json @@ -12,7 +12,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Require administrators or appropriately delegated users to create new tenants.", @@ -32,7 +32,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Microsoft Entra ID is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed.", @@ -52,7 +52,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Ensures that two alternate forms of identification are provided before allowing a password reset.", @@ -72,7 +72,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Microsoft Entra ID Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy.", @@ -92,7 +92,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0.", @@ -112,7 +112,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Ensure that users are notified on their primary and secondary emails on password resets.", @@ -132,7 +132,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Ensure that all Global Administrators are notified if any other administrator resets their password.", @@ -154,7 +154,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Require administrators to provide consent for applications before use.", @@ -176,7 +176,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Allow users to provide consent for selected permissions when a request is coming from a verified publisher.", @@ -196,7 +196,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Require administrators to provide consent for the apps before use.", @@ -218,7 +218,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Require administrators or appropriately delegated users to register third-party applications.", @@ -240,7 +240,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Limit guest user permissions.", @@ -262,7 +262,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Restrict invitations to users with specific administrative roles only.", @@ -282,7 +282,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Restrict access to the Microsoft Entra ID administration center to administrators only. **NOTE**: This only affects access to the Entra ID administrator's web portal. This setting does not prohibit privileged users from using other methods such as Rest API or Powershell to obtain sensitive information from Microsoft Entra ID.", @@ -302,7 +302,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Restrict access to group web interface in the Access Panel portal.", @@ -324,7 +324,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Restrict security group creation to administrators only.", @@ -344,7 +344,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Restrict security group management to administrators only.", @@ -366,7 +366,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Restrict Microsoft 365 group creation to administrators only.", @@ -386,7 +386,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "Joining or registering devices to Microsoft Entra ID should require Multi-factor authentication.", @@ -408,7 +408,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Automated", "Description": "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.", @@ -430,7 +430,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration.", @@ -450,7 +450,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Microsoft Entra ID.", @@ -472,7 +472,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "Profile": "Level 1", "AssessmentStatus": "Manual", "Description": "This recommendation aims to maintain a balance between security and operational efficiency by ensuring that a minimum of 2 and a maximum of 4 users are assigned the Global Administrator role in Microsoft Entra ID. Having at least two Global Administrators ensures redundancy, while limiting the number to four reduces the risk of excessive privileged access.", @@ -494,7 +494,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.1 Security Defaults Security Defaults", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -517,7 +517,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.1 Security Defaults Security Defaults", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -540,7 +540,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.1 Security Defaults Security Defaults", "Profile": "Level 2", "AssessmentStatus": "Manual", @@ -561,7 +561,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.1 Security Defaults Security Defaults", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -584,7 +584,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -605,7 +605,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -626,7 +626,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -647,7 +647,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -668,7 +668,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -691,7 +691,7 @@ ], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", @@ -712,7 +712,7 @@ "Checks": [], "Attributes": [ { - "Section": "1.Identity and Access Management", + "Section": "1. Identity and Access Management", "SubSection": "1.2 Conditional Access", "Profile": "Level 1", "AssessmentStatus": "Manual", diff --git a/prowler/compliance/azure/cis_3.0_azure.json b/prowler/compliance/azure/cis_3.0_azure.json index a72b5907ac..4175dd2a7e 100644 --- a/prowler/compliance/azure/cis_3.0_azure.json +++ b/prowler/compliance/azure/cis_3.0_azure.json @@ -3481,7 +3481,7 @@ "Checks": [], "Attributes": [ { - "Section": "10", + "Section": "10. Miscellaneous", "Profile": "Level 2", "AssessmentStatus": "Manual", "Description": "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion.", From d740bf84c35518f10d2d5efd983b04f31a062753 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 25 Apr 2025 15:24:47 +0200 Subject: [PATCH 219/359] feat: add new M365 to the provider overview table (#7615) --- .../overview/provider-overview/provider-overview.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/components/overview/provider-overview/provider-overview.tsx b/ui/components/overview/provider-overview/provider-overview.tsx index 48333c5fbc..41d518eb8a 100644 --- a/ui/components/overview/provider-overview/provider-overview.tsx +++ b/ui/components/overview/provider-overview/provider-overview.tsx @@ -8,6 +8,7 @@ import { AzureProviderBadge, GCPProviderBadge, KS8ProviderBadge, + M365ProviderBadge, } from "@/components/icons/providers-badge"; import { CustomButton } from "@/components/ui/custom/custom-button"; import { ProviderOverviewProps } from "@/types"; @@ -26,6 +27,8 @@ export const ProvidersOverview = ({ return ; case "azure": return ; + case "m365": + return ; case "gcp": return ; case "kubernetes": @@ -38,6 +41,7 @@ export const ProvidersOverview = ({ const providers = [ { id: "aws", name: "AWS" }, { id: "azure", name: "Azure" }, + { id: "m365", name: "M365" }, { id: "gcp", name: "GCP" }, { id: "kubernetes", name: "Kubernetes" }, ]; From 90453fd07e78d5ee9ee33fe9be1b30472426c9b6 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 25 Apr 2025 15:29:24 +0200 Subject: [PATCH 220/359] feat(teams): add new check `teams_meeting_chat_anonymous_users_disabled` (#7579) Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...hat_anonymous_users_disabled.metadata.json | 30 ++++ ...s_meeting_chat_anonymous_users_disabled.py | 48 ++++++ .../m365/services/teams/teams_service.py | 4 + ...ting_chat_anonymous_users_disabled_test.py | 159 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 244 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 93d065e206..b353d53e23 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567) - Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568) - Add new check `teams_meeting_dial_in_lobby_bypass_disabled` [(#7571)](https://github.com/prowler-cloud/prowler/pull/7571) +- Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.metadata.json new file mode 100644 index 0000000000..38258f5706 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_chat_anonymous_users_disabled", + "CheckTitle": "Ensure meeting chat does not allow anonymous users", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure meeting chat does not allow anonymous users.", + "Risk": "Allowing anonymous users to participate in meeting chat can expose sensitive information and increase the risk of inappropriate content being shared by unverified participants.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -MeetingChatEnabledType 'EnabledExceptAnonymous'", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting engagement verify that Meeting chat is set to On for everyone but anonymous users.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict chat access during meetings to only authenticated and authorized users. Disable chat capabilities for anonymous users to maintain confidentiality and prevent misuse.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.py new file mode 100644 index 0000000000..9eacc6b8af --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled.py @@ -0,0 +1,48 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_chat_anonymous_users_disabled(Check): + """Check if meeting chat does not allow anonymous users. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for meeting chat does not allow anonymous users. + + This method checks if meeting chat does not allow anonymous users. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = "Meeting chat allows anonymous users." + + allowed_meeting_chat_settings = { + "EnabledExceptAnonymous", + "EnabledInMeetingOnlyForAllExceptAnonymous", + } + + if ( + global_meeting_policy.meeting_chat_enabled_type + in allowed_meeting_chat_settings + ): + report.status = "PASS" + report.status_extended = "Meeting chat does not allow anonymous users." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index e3bd078742..22c4c3d6c0 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -58,6 +58,9 @@ class Teams(M365Service): allow_pstn_users_to_bypass_lobby=global_meeting_policy.get( "AllowPSTNUsersToBypassLobby", True ), + meeting_chat_enabled_type=global_meeting_policy.get( + "MeetingChatEnabledType", "EnabledForEveryone" + ), ) except Exception as error: logger.error( @@ -103,6 +106,7 @@ class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_start_meeting: bool = True allow_external_users_to_bypass_lobby: str = "Everyone" allow_pstn_users_to_bypass_lobby: bool = True + meeting_chat_enabled_type: str = "EnabledForEveryone" class UserSettings(BaseModel): diff --git a/tests/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled_test.py new file mode 100644 index 0000000000..cecc4ea919 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_chat_anonymous_users_disabled/teams_meeting_chat_anonymous_users_disabled_test.py @@ -0,0 +1,159 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_chat_anonymous_users_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled import ( + teams_meeting_chat_anonymous_users_disabled, + ) + + check = teams_meeting_chat_anonymous_users_disabled() + result = check.execute() + assert len(result) == 0 + + def test_meeting_chat_allows_anonymous_users(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled import ( + teams_meeting_chat_anonymous_users_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + meeting_chat_enabled_type="EnabledForEveryone" + ) + + check = teams_meeting_chat_anonymous_users_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == "Meeting chat allows anonymous users." + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_meeting_chat_does_not_allow_anonymous_users_enabled_except_anonymous(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled import ( + teams_meeting_chat_anonymous_users_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + meeting_chat_enabled_type="EnabledExceptAnonymous" + ) + + check = teams_meeting_chat_anonymous_users_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Meeting chat does not allow anonymous users." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_meeting_chat_does_not_allow_anonymous_users_enabled_in_meeting_only(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_chat_anonymous_users_disabled.teams_meeting_chat_anonymous_users_disabled import ( + teams_meeting_chat_anonymous_users_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + meeting_chat_enabled_type="EnabledInMeetingOnlyForAllExceptAnonymous" + ) + + check = teams_meeting_chat_anonymous_users_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Meeting chat does not allow anonymous users." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index 5ddee2b209..a4fb74a7b5 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -30,6 +30,7 @@ def mock_get_global_meeting_policy(_): allow_anonymous_users_to_start_meeting=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, + meeting_chat_enabled_type="EnabledExceptAnonymous", ) @@ -126,5 +127,6 @@ class Test_Teams_Service: allow_anonymous_users_to_start_meeting=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, + meeting_chat_enabled_type="EnabledExceptAnonymous", ) teams_client.powershell.close() From a51a185f495f42029928700d67f119c4b601ef2c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:44:25 +0200 Subject: [PATCH 221/359] fix(powershell): handle m365 provider execution and logging (#7602) Co-authored-by: MrCloudSec --- prowler/lib/powershell/powershell.py | 83 ++++++++-- .../m365/lib/powershell/m365_powershell.py | 55 ++++--- prowler/providers/m365/lib/service/service.py | 6 +- prowler/providers/m365/m365_provider.py | 7 +- .../services/defender/defender_service.py | 30 ++-- .../services/exchange/exchange_service.py | 18 ++- .../m365/services/purview/purview_service.py | 9 +- .../m365/services/teams/teams_service.py | 15 +- tests/lib/powershell/powershell_test.py | 150 ++++++++++++++++-- .../lib/powershell/m365_powershell_test.py | 94 ++++++++--- 10 files changed, 365 insertions(+), 102 deletions(-) diff --git a/prowler/lib/powershell/powershell.py b/prowler/lib/powershell/powershell.py index 373fc97183..26cd2fe952 100644 --- a/prowler/lib/powershell/powershell.py +++ b/prowler/lib/powershell/powershell.py @@ -4,6 +4,9 @@ import queue import re import subprocess import threading +from typing import Union + +from prowler.lib.logger import logger class PowerShellSession: @@ -100,7 +103,9 @@ class PowerShellSession: ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") return ansi_escape.sub("", text) - def execute(self, command: str) -> dict: + def execute( + self, command: str, json_parse: bool = False, timeout: int = 10 + ) -> Union[str, dict]: """ Send a command to PowerShell and retrieve its output. @@ -120,31 +125,41 @@ class PowerShellSession: """ self.process.stdin.write(f"{command}\n") self.process.stdin.write(f"Write-Output '{self.END}'\n") - return self.json_parse_output(self.read_output()) + self.process.stdin.write(f"Write-Error '{self.END}'\n") + return ( + self.json_parse_output(self.read_output(timeout=timeout)) + if json_parse + else self.read_output(timeout=timeout) + ) def read_output(self, timeout: int = 10, default: str = "") -> str: """ Read output from a process with timeout functionality. - This method reads lines from process stdout until it encounters the END marker - or the stream ends. If reading takes longer than the timeout period, the method - returns a default value while allowing the reading to continue in the background. + This method reads lines from process stdout and stderr in separate threads until it encounters + the END marker for each stream. If reading stdout takes longer than the timeout period, + the method returns a default value while allowing the reading to continue in the background. + + Any errors from stderr are logged but do not affect the return value. Args: - timeout (int, optional): Maximum time in seconds to wait for output. + timeout (int, optional): Maximum time in seconds to wait for stdout output. Defaults to 10. - default (str, optional): Value to return if timeout occurs. + default (str, optional): Value to return if stdout timeout occurs. Defaults to empty string. Returns: - str: Concatenated output lines or default value if timeout occurs. + str: The stdout output if available, otherwise the default value. + Errors from stderr are logged but not returned. Note: - This method uses a daemon thread to read the output asynchronously, + This method uses daemon threads to read stdout and stderr asynchronously, ensuring that the main thread is not blocked. """ output_lines = [] result_queue = queue.Queue() + error_lines = [] + error_queue = queue.Queue() def reader_thread(): try: @@ -154,17 +169,35 @@ class PowerShellSession: break output_lines.append(line) result_queue.put("\n".join(output_lines)) - except Exception as e: - result_queue.put(str(e)) + except Exception as error: + result_queue.put(str(error)) + + def error_reader_thread(): + try: + while True: + line = self.remove_ansi(self.process.stderr.readline().strip()) + if line == f"Write-Error: {self.END}": + break + error_lines.append(line) + error_queue.put("\n".join(error_lines)) + except Exception as error: + error_queue.put(str(error)) thread = threading.Thread(target=reader_thread) thread.daemon = True thread.start() - try: - return result_queue.get(timeout=timeout) - except queue.Empty: - return default + error_thread = threading.Thread(target=error_reader_thread) + error_thread.daemon = True + error_thread.start() + + result = result_queue.get(timeout=timeout) or default + error_result = error_queue.get(timeout=1) + + if error_result: + logger.error(f"PowerShell error output: {error_result}") + + return result def json_parse_output(self, output: str) -> dict: """ @@ -179,13 +212,29 @@ class PowerShellSession: Returns: dict: Parsed JSON object if found, otherwise an empty dictionary. + Raises: + JSONDecodeError: If the JSON parsing fails. + Example: >>> json_parse_output('Some text {"key": "value"} more text') {"key": "value"} """ + if output == "": + return {} + json_match = re.search(r"(\[.*\]|\{.*\})", output, re.DOTALL) - if json_match: - return json.loads(json_match.group(1)) + if not json_match: + logger.error( + f"Unexpected PowerShell output: {output}\n", + ) + else: + try: + return json.loads(json_match.group(1)) + except json.JSONDecodeError as error: + logger.error( + f"Error parsing PowerShell output as JSON: {str(error)}\n", + ) + return {} def close(self) -> None: diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index b3a7db9689..982e26672b 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -84,16 +84,14 @@ class M365PowerShell(PowerShellSession): bool: True if credentials are valid and authentication succeeds, False otherwise. """ self.execute( - f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString\n' + f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString' ) self.execute( f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' ) - self.process.stdin.write( - 'Write-Output "$($credential.GetNetworkCredential().Password)"\n' + decrypted_password = self.execute( + 'Write-Output "$($credential.GetNetworkCredential().Password)"' ) - self.process.stdin.write(f"Write-Output '{self.END}'\n") - decrypted_password = self.read_output() app = msal.ConfidentialClientApplication( client_id=credentials.client_id, @@ -154,7 +152,9 @@ class M365PowerShell(PowerShellSession): "AllowGoogleDrive": true } """ - return self.execute("Get-CsTeamsClientConfiguration | ConvertTo-Json") + return self.execute( + "Get-CsTeamsClientConfiguration | ConvertTo-Json", json_parse=True + ) def get_global_meeting_policy(self) -> dict: """ @@ -172,7 +172,8 @@ class M365PowerShell(PowerShellSession): } """ return self.execute( - "Get-CsTeamsMeetingPolicy -Identity Global | ConvertTo-Json" + "Get-CsTeamsMeetingPolicy -Identity Global | ConvertTo-Json", + json_parse=True, ) def get_user_settings(self) -> dict: @@ -190,7 +191,9 @@ class M365PowerShell(PowerShellSession): "AllowExternalAccess": true } """ - return self.execute("Get-CsTenantFederationConfiguration | ConvertTo-Json") + return self.execute( + "Get-CsTenantFederationConfiguration | ConvertTo-Json", json_parse=True + ) def connect_exchange_online(self) -> dict: """ @@ -222,7 +225,8 @@ class M365PowerShell(PowerShellSession): } """ return self.execute( - "Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json" + "Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json", + json_parse=True, ) def get_malware_filter_policy(self) -> dict: @@ -241,7 +245,7 @@ class M365PowerShell(PowerShellSession): "Identity": "Default" } """ - return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json") + return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json", json_parse=True) def get_outbound_spam_filter_policy(self) -> dict: """ @@ -261,7 +265,9 @@ class M365PowerShell(PowerShellSession): "NotifyOutboundSpamRecipients": [] } """ - return self.execute("Get-HostedOutboundSpamFilterPolicy | ConvertTo-Json") + return self.execute( + "Get-HostedOutboundSpamFilterPolicy | ConvertTo-Json", json_parse=True + ) def get_outbound_spam_filter_rule(self) -> dict: """ @@ -278,7 +284,9 @@ class M365PowerShell(PowerShellSession): "State": "Enabled" } """ - return self.execute("Get-HostedOutboundSpamFilterRule | ConvertTo-Json") + return self.execute( + "Get-HostedOutboundSpamFilterRule | ConvertTo-Json", json_parse=True + ) def get_antiphishing_policy(self) -> dict: """ @@ -303,7 +311,7 @@ class M365PowerShell(PowerShellSession): "IsDefault": false } """ - return self.execute("Get-AntiPhishPolicy | ConvertTo-Json") + return self.execute("Get-AntiPhishPolicy | ConvertTo-Json", json_parse=True) def get_antiphishing_rules(self) -> dict: """ @@ -321,7 +329,7 @@ class M365PowerShell(PowerShellSession): "State": Enabled, } """ - return self.execute("Get-AntiPhishRule | ConvertTo-Json") + return self.execute("Get-AntiPhishRule | ConvertTo-Json", json_parse=True) def get_organization_config(self) -> dict: """ @@ -340,7 +348,7 @@ class M365PowerShell(PowerShellSession): "AuditDisabled": false } """ - return self.execute("Get-OrganizationConfig | ConvertTo-Json") + return self.execute("Get-OrganizationConfig | ConvertTo-Json", json_parse=True) def get_mailbox_audit_config(self) -> dict: """ @@ -359,7 +367,9 @@ class M365PowerShell(PowerShellSession): "AuditBypassEnabled": false } """ - return self.execute("Get-MailboxAuditBypassAssociation | ConvertTo-Json") + return self.execute( + "Get-MailboxAuditBypassAssociation | ConvertTo-Json", json_parse=True + ) def get_external_mail_config(self) -> dict: """ @@ -377,7 +387,7 @@ class M365PowerShell(PowerShellSession): "ExternalMailTagEnabled": true } """ - return self.execute("Get-ExternalInOutlook | ConvertTo-Json") + return self.execute("Get-ExternalInOutlook | ConvertTo-Json", json_parse=True) def get_transport_rules(self) -> dict: """ @@ -396,7 +406,7 @@ class M365PowerShell(PowerShellSession): "SenderDomainIs": ["example.com"] } """ - return self.execute("Get-TransportRule | ConvertTo-Json") + return self.execute("Get-TransportRule | ConvertTo-Json", json_parse=True) def get_connection_filter_policy(self) -> dict: """ @@ -415,7 +425,8 @@ class M365PowerShell(PowerShellSession): } """ return self.execute( - "Get-HostedConnectionFilterPolicy -Identity Default | ConvertTo-Json" + "Get-HostedConnectionFilterPolicy -Identity Default | ConvertTo-Json", + json_parse=True, ) def get_dkim_config(self) -> dict: @@ -434,7 +445,7 @@ class M365PowerShell(PowerShellSession): "Enabled": true } """ - return self.execute("Get-DkimSigningConfig | ConvertTo-Json") + return self.execute("Get-DkimSigningConfig | ConvertTo-Json", json_parse=True) def get_inbound_spam_filter_policy(self) -> dict: """ @@ -452,4 +463,6 @@ class M365PowerShell(PowerShellSession): "AllowedSenderDomains": "[]" } """ - return self.execute("Get-HostedContentFilterPolicy | ConvertTo-Json") + return self.execute( + "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True + ) diff --git a/prowler/providers/m365/lib/service/service.py b/prowler/providers/m365/lib/service/service.py index 02aeb2762c..b218aac283 100644 --- a/prowler/providers/m365/lib/service/service.py +++ b/prowler/providers/m365/lib/service/service.py @@ -13,5 +13,7 @@ class M365Service: self.audit_config = provider.audit_config self.fixer_config = provider.fixer_config - if provider.credentials: - self.powershell = M365PowerShell(provider.credentials) + # Initialize PowerShell client only if credentials are available + self.powershell = ( + M365PowerShell(provider.credentials) if provider.credentials else None + ) diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py index 8608c88180..4898b5c311 100644 --- a/prowler/providers/m365/m365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -100,7 +100,7 @@ class M365Provider(Provider): _audit_config: dict _region_config: M365RegionConfig _mutelist: M365Mutelist - _credentials: M365Credentials + _credentials: M365Credentials = {} # TODO: this is not optional, enforce for all providers audit_metadata: Audit_Metadata @@ -447,8 +447,11 @@ class M365Provider(Provider): f"M365 Region: {Fore.YELLOW}{self.region_config.name}{Style.RESET_ALL}", f"M365 Tenant Domain: {Fore.YELLOW}{self._identity.tenant_domain}{Style.RESET_ALL} M365 Tenant ID: {Fore.YELLOW}{self._identity.tenant_id}{Style.RESET_ALL}", f"M365 Identity Type: {Fore.YELLOW}{self._identity.identity_type}{Style.RESET_ALL} M365 Identity ID: {Fore.YELLOW}{self._identity.identity_id}{Style.RESET_ALL}", - f"M365 User: {Fore.YELLOW}{self.credentials.user}{Style.RESET_ALL}", ] + if self.credentials and self.credentials.user: + report_lines.append( + f"M365 User: {Fore.YELLOW}{self.credentials.user}{Style.RESET_ALL}" + ) report_title = ( f"{Style.BRIGHT}Using the M365 credentials below:{Style.RESET_ALL}" ) diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index 4fc86aa51c..3ed0eee58b 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -10,16 +10,26 @@ from prowler.providers.m365.m365_provider import M365Provider class Defender(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) - self.powershell.connect_exchange_online() - self.malware_policies = self._get_malware_filter_policy() - self.outbound_spam_policies = self._get_outbound_spam_filter_policy() - self.outbound_spam_rules = self._get_outbound_spam_filter_rule() - self.antiphishing_policies = self._get_antiphising_policy() - self.antiphising_rules = self._get_antiphising_rules() - self.inbound_spam_policies = self._get_inbound_spam_filter_policy() - self.connection_filter_policy = self._get_connection_filter_policy() - self.dkim_configurations = self._get_dkim_config() - self.powershell.close() + self.malware_policies = [] + self.outbound_spam_policies = {} + self.outbound_spam_rules = {} + self.antiphishing_policies = {} + self.antiphising_rules = {} + self.connection_filter_policy = None + self.dkim_configurations = [] + self.inbound_spam_policies = [] + + if self.powershell: + self.powershell.connect_exchange_online() + self.malware_policies = self._get_malware_filter_policy() + self.outbound_spam_policies = self._get_outbound_spam_filter_policy() + self.outbound_spam_rules = self._get_outbound_spam_filter_rule() + self.antiphishing_policies = self._get_antiphising_policy() + self.antiphising_rules = self._get_antiphising_rules() + self.connection_filter_policy = self._get_connection_filter_policy() + self.dkim_configurations = self._get_dkim_config() + self.inbound_spam_policies = self._get_inbound_spam_filter_policy() + self.powershell.close() def _get_malware_filter_policy(self): logger.info("M365 - Getting Defender malware filter policy...") diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index c1d544787f..5bd8cada6a 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -10,12 +10,18 @@ from prowler.providers.m365.m365_provider import M365Provider class Exchange(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) - self.powershell.connect_exchange_online() - self.organization_config = self._get_organization_config() - self.mailboxes_config = self._get_mailbox_audit_config() - self.external_mail_config = self._get_external_mail_config() - self.transport_rules = self._get_transport_rules() - self.powershell.close() + self.organization_config = None + self.mailboxes_config = [] + self.external_mail_config = [] + self.transport_rules = [] + + if self.powershell: + self.powershell.connect_exchange_online() + self.organization_config = self._get_organization_config() + self.mailboxes_config = self._get_mailbox_audit_config() + self.external_mail_config = self._get_external_mail_config() + self.transport_rules = self._get_transport_rules() + self.powershell.close() def _get_organization_config(self): logger.info("Microsoft365 - Getting Exchange Organization configuration...") diff --git a/prowler/providers/m365/services/purview/purview_service.py b/prowler/providers/m365/services/purview/purview_service.py index 2323b28dce..138305c899 100644 --- a/prowler/providers/m365/services/purview/purview_service.py +++ b/prowler/providers/m365/services/purview/purview_service.py @@ -8,9 +8,12 @@ from prowler.providers.m365.m365_provider import M365Provider class Purview(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) - self.powershell.connect_exchange_online() - self.audit_log_config = self._get_audit_log_config() - self.powershell.close() + self.audit_log_config = None + + if self.powershell: + self.powershell.connect_exchange_online() + self.audit_log_config = self._get_audit_log_config() + self.powershell.close() def _get_audit_log_config(self): logger.info("M365 - Getting Admin Audit Log settings...") diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 22c4c3d6c0..df65cf400b 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -8,11 +8,16 @@ from prowler.providers.m365.m365_provider import M365Provider class Teams(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) - self.powershell.connect_microsoft_teams() - self.teams_settings = self._get_teams_client_configuration() - self.global_meeting_policy = self._get_global_meeting_policy() - self.user_settings = self._get_user_settings() - self.powershell.close() + self.teams_settings = None + self.global_meeting_policy = None + self.user_settings = None + + if self.powershell: + self.powershell.connect_microsoft_teams() + self.teams_settings = self._get_teams_client_configuration() + self.global_meeting_policy = self._get_global_meeting_policy() + self.user_settings = self._get_user_settings() + self.powershell.close() def _get_teams_client_configuration(self): logger.info("M365 - Getting Teams settings...") diff --git a/tests/lib/powershell/powershell_test.py b/tests/lib/powershell/powershell_test.py index 6dab9349a0..49108e1cd2 100644 --- a/tests/lib/powershell/powershell_test.py +++ b/tests/lib/powershell/powershell_test.py @@ -58,34 +58,109 @@ class TestPowerShellSession: @patch("subprocess.Popen") def test_execute(self, mock_popen): + """Test the execute method with various scenarios: + - Normal command execution + - JSON parsing enabled + - Timeout handling + - Error handling + """ + # Setup mock_process = MagicMock() mock_popen.return_value = mock_process session = PowerShellSession() - command = "Get-Command" - expected_output = '{"Name": "Get-Command"}' - with patch.object(session, "read_output", return_value=expected_output): - result = session.execute(command) - - mock_process.stdin.write.assert_any_call(f"{command}\n") + # Test 1: Normal command execution + mock_process.stdout.readline.side_effect = ["Hello World\n", f"{session.END}\n"] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + result = session.execute("Get-Command") + assert result == "Hello World" + mock_process.stdin.write.assert_any_call("Get-Command\n") mock_process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") - assert result == {"Name": "Get-Command"} + mock_process.stdin.write.assert_any_call(f"Write-Error '{session.END}'\n") + + # Test 2: JSON parsing enabled + mock_process.stdout.readline.side_effect = [ + '{"key": "value"}\n', + f"{session.END}\n", + ] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + with patch.object( + session, "json_parse_output", return_value={"key": "value"} + ) as mock_json_parse: + result = session.execute("Get-Command", json_parse=True) + assert result == {"key": "value"} + mock_json_parse.assert_called_once_with('{"key": "value"}') + + # Test 3: Timeout handling + mock_process.stdout.readline.side_effect = ["test output\n"] # No END marker + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.execute("Get-Command", timeout=0.1) + assert result == "" + + # Test 4: Error handling + mock_process.stdout.readline.side_effect = ["\n", f"{session.END}\n"] + mock_process.stderr.readline.side_effect = [ + "Write-Error: This is an error\n", + f"Write-Error: {session.END}\n", + ] + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.execute("Get-Command") + assert result == "" + mock_error.assert_called_once_with( + "PowerShell error output: Write-Error: This is an error" + ) + session.close() @patch("subprocess.Popen") def test_read_output(self, mock_popen): + """Test the read_output method with various scenarios: + - Normal stdout output + - Error in stderr + - Timeout in stdout + - Empty output + """ + # Setup mock_process = MagicMock() mock_popen.return_value = mock_process session = PowerShellSession() - # Test normal output - with patch.object(session, "read_output", return_value="test@example.com"): - assert session.read_output() == "test@example.com" + # Test 1: Normal stdout output + mock_process.stdout.readline.side_effect = ["Hello World\n", f"{session.END}\n"] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + result = session.read_output() + assert result == "Hello World" + + # Test 2: Error in stderr + mock_process.stdout.readline.side_effect = ["\n", f"{session.END}\n"] + mock_process.stderr.readline.side_effect = [ + "Write-Error: This is an error\n", + f"Write-Error: {session.END}\n", + ] + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.read_output() + assert result == "" + mock_error.assert_called_once_with( + "PowerShell error output: Write-Error: This is an error" + ) + + # Test 3: Timeout in stdout + mock_process.stdout.readline.side_effect = ["test output\n"] # No END marker + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.read_output(timeout=0.1, default="timeout") + assert result == "timeout" + + # Test 4: Empty output + mock_process.stdout.readline.side_effect = [f"{session.END}\n"] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.read_output() + assert result == "" - # Test timeout - mock_process.stdout.readline.return_value = "test output\n" - with patch.object(session, "remove_ansi", return_value="test output"): - assert session.read_output(timeout=0.1, default="") == "" session.close() @patch("subprocess.Popen") @@ -112,6 +187,53 @@ class TestPowerShellSession: assert result == expected session.close() + @patch("subprocess.Popen") + def test_json_parse_output_logging(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + # Test warning for non-JSON output + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.json_parse_output("some text without json") + assert result == {} + mock_error.assert_called_once_with( + "Unexpected PowerShell output: some text without json\n" + ) + + session.close() + + @patch("subprocess.Popen") + def test_json_parse_output_with_text_around_json(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + # Test JSON extraction from text with surrounding content + result = session.json_parse_output('some text {"key": "value"} more text') + assert result == {"key": "value"} + + result = session.json_parse_output('prefix [{"key": "value"}] suffix') + assert result == [{"key": "value"}] + + # Test non-JSON text returns empty dict + result = session.json_parse_output("just some text") + assert result == {} + + session.close() + + @patch("subprocess.Popen") + def test_json_parse_output_empty(self, mock_popen): + mock_process = MagicMock() + mock_popen.return_value = mock_process + session = PowerShellSession() + + # Test empty string + result = session.json_parse_output("") + assert result == {} + + session.close() + @patch("subprocess.Popen") def test_close(self, mock_popen): mock_process = MagicMock() diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py index 56cc28ef33..72f5e72810 100644 --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -98,23 +98,28 @@ class Testm365PowerShell: ) session = M365PowerShell(credentials) - session.execute = MagicMock() - session.process.stdin.write = MagicMock() + # Mock read_output to return the decrypted password session.read_output = MagicMock(return_value="decrypted_password") - assert session.test_credentials(credentials) is True + # Mock execute to return the result of read_output + session.execute = MagicMock(side_effect=lambda _: session.read_output()) + # Execute the test + result = session.test_credentials(credentials) + assert result is True + + # Verify execute was called with the correct commands session.execute.assert_any_call( - f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString\n' + f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString' ) session.execute.assert_any_call( f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' ) - session.process.stdin.write.assert_any_call( - 'Write-Output "$($credential.GetNetworkCredential().Password)"\n' + session.execute.assert_any_call( + 'Write-Output "$($credential.GetNetworkCredential().Password)"' ) - session.process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") + # Verify MSAL was called with the correct parameters mock_msal.assert_called_once_with( client_id="test_client_id", client_credential="test_client_secret", @@ -148,7 +153,13 @@ class Testm365PowerShell: ) session = M365PowerShell(credentials) - session.execute = MagicMock() + # Mock the execute method to return the decrypted password + def mock_execute(command, *args, **kwargs): + if "Write-Output" in command: + return "decrypted_password" + return None + + session.execute = MagicMock(side_effect=mock_execute) session.process.stdin.write = MagicMock() session.read_output = MagicMock(return_value="decrypted_password") @@ -191,7 +202,13 @@ class Testm365PowerShell: ) session = M365PowerShell(credentials) - session.execute = MagicMock() + # Mock the execute method to return the decrypted password + def mock_execute(command, *args, **kwargs): + if "Write-Output" in command: + return "decrypted_password" + return None + + session.execute = MagicMock(side_effect=mock_execute) session.process.stdin.write = MagicMock() session.read_output = MagicMock(return_value="decrypted_password") @@ -207,6 +224,7 @@ class Testm365PowerShell: password="decrypted_password", scopes=["https://graph.microsoft.com/.default"], ) + session.close() @patch("subprocess.Popen") @@ -233,31 +251,63 @@ class Testm365PowerShell: credentials = M365Credentials(user="test@example.com", passwd="test_password") session = M365PowerShell(credentials) command = "Get-Command" - expected_output = '{"Name": "Get-Command"}' + expected_output = {"Name": "Get-Command"} - with patch.object(session, "read_output", return_value=expected_output): + with patch.object(session, "execute", return_value=expected_output): result = session.execute(command) - - mock_process.stdin.write.assert_any_call(f"{command}\n") - mock_process.stdin.write.assert_any_call(f"Write-Output '{session.END}'\n") - assert result == {"Name": "Get-Command"} + assert result == expected_output session.close() @patch("subprocess.Popen") def test_read_output(self, mock_popen): + """Test the read_output method with various scenarios: + - Normal stdout output + - Error in stderr + - Timeout in stdout + - Empty output + """ + # Setup mock_process = MagicMock() mock_popen.return_value = mock_process credentials = M365Credentials(user="test@example.com", passwd="test_password") session = M365PowerShell(credentials) - # Test normal output - with patch.object(session, "read_output", return_value="test@example.com"): - assert session.read_output() == "test@example.com" + # Test 1: Normal stdout output + mock_process.stdout.readline.side_effect = [ + "test@example.com\n", + f"{session.END}\n", + ] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + result = session.read_output() + assert result == "test@example.com" + + # Test 2: Error in stderr + mock_process.stdout.readline.side_effect = ["\n", f"{session.END}\n"] + mock_process.stderr.readline.side_effect = [ + "Write-Error: Authentication failed\n", + f"Write-Error: {session.END}\n", + ] + with patch.object(session, "remove_ansi", side_effect=lambda x: x): + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.read_output() + assert result == "" + mock_error.assert_called_once_with( + "PowerShell error output: Write-Error: Authentication failed" + ) + + # Test 3: Timeout in stdout + mock_process.stdout.readline.side_effect = ["test output\n"] # No END marker + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.read_output(timeout=0.1, default="timeout") + assert result == "timeout" + + # Test 4: Empty output + mock_process.stdout.readline.side_effect = [f"{session.END}\n"] + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.read_output() + assert result == "" - # Test timeout - mock_process.stdout.readline.return_value = "test output\n" - with patch.object(session, "remove_ansi", return_value="test output"): - assert session.read_output(timeout=0.1, default="") == "" session.close() @patch("subprocess.Popen") From 51db81aa5cc3b715fc6c8955f57542e0641fd07d Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:59:36 +0200 Subject: [PATCH 222/359] feat(teams): add new check `teams_meeting_external_control_disabled` (#7604) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ng_external_control_disabled.metadata.json | 30 +++++ ...teams_meeting_external_control_disabled.py | 46 +++++++ .../m365/services/teams/teams_service.py | 4 + ..._meeting_external_control_disabled_test.py | 118 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 201 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index b353d53e23..ccf6a05f3b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567) - Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568) - Add new check `teams_meeting_dial_in_lobby_bypass_disabled` [(#7571)](https://github.com/prowler-cloud/prowler/pull/7571) +- Add new check `teams_meeting_external_control_disabled` [(#7604)](https://github.com/prowler-cloud/prowler/pull/7604) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.metadata.json new file mode 100644 index 0000000000..342a26dbe1 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_external_control_disabled", + "CheckTitle": "Ensure external participants can't give or request control", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure external participants can't give or request control in Teams meetings.", + "Risk": "Allowing external participants to give or request control during meetings could lead to unauthorized content sharing or malicious actions by external users.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowExternalParticipantGiveRequestControl $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under content sharing set External participants can give or request control to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable the ability for external participants to give or request control during Teams meetings to prevent unauthorized content sharing and maintain meeting security.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.py new file mode 100644 index 0000000000..c08ee4ee32 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled.py @@ -0,0 +1,46 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_external_control_disabled(Check): + """Check if external participants can't give or request control in meetings. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for external participants' control permissions in meetings. + + This method checks if external participants are prevented from giving or requesting control in meetings. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "External participants can give or request control." + ) + + if ( + not global_meeting_policy.allow_external_participant_give_request_control + ): + report.status = "PASS" + report.status_extended = ( + "External participants cannot give or request control." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index df65cf400b..1e61f7139a 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -57,6 +57,9 @@ class Teams(M365Service): allow_anonymous_users_to_start_meeting=global_meeting_policy.get( "AllowAnonymousUsersToStartMeeting", True ), + allow_external_participant_give_request_control=global_meeting_policy.get( + "AllowExternalParticipantGiveRequestControl", True + ), allow_external_users_to_bypass_lobby=global_meeting_policy.get( "AutoAdmittedUsers", "Everyone" ), @@ -109,6 +112,7 @@ class TeamsSettings(BaseModel): class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_join_meeting: bool = True allow_anonymous_users_to_start_meeting: bool = True + allow_external_participant_give_request_control: bool = True allow_external_users_to_bypass_lobby: str = "Everyone" allow_pstn_users_to_bypass_lobby: bool = True meeting_chat_enabled_type: str = "EnabledForEveryone" diff --git a/tests/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled_test.py new file mode 100644 index 0000000000..c2a3d783f3 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_external_control_disabled/teams_meeting_external_control_disabled_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_external_control_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled import ( + teams_meeting_external_control_disabled, + ) + + check = teams_meeting_external_control_disabled() + result = check.execute() + assert len(result) == 0 + + def test_external_participants_can_control(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled import ( + teams_meeting_external_control_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_participant_give_request_control=True + ) + + check = teams_meeting_external_control_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External participants can give or request control." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_external_participants_cannot_control(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_control_disabled.teams_meeting_external_control_disabled import ( + teams_meeting_external_control_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_participant_give_request_control=False + ) + + check = teams_meeting_external_control_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External participants cannot give or request control." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index a4fb74a7b5..5bf948383d 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -28,6 +28,7 @@ def mock_get_global_meeting_policy(_): return GlobalMeetingPolicy( allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, + allow_external_participant_give_request_control=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", @@ -125,6 +126,7 @@ class Test_Teams_Service: assert teams_client.global_meeting_policy == GlobalMeetingPolicy( allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, + allow_external_participant_give_request_control=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", From cdcc5c6e355864547c3759321efc8d60d960569a Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:30:38 +0200 Subject: [PATCH 223/359] feat(teams): add new check `teams_meeting_external_chat_disabled` (#7605) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...eting_external_chat_disabled.metadata.json | 30 +++++ .../teams_meeting_external_chat_disabled.py | 44 +++++++ .../m365/services/teams/teams_service.py | 4 + ...ams_meeting_external_chat_disabled_test.py | 118 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 199 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index ccf6a05f3b..5cb5a4b358 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -31,6 +31,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568) - Add new check `teams_meeting_dial_in_lobby_bypass_disabled` [(#7571)](https://github.com/prowler-cloud/prowler/pull/7571) - Add new check `teams_meeting_external_control_disabled` [(#7604)](https://github.com/prowler-cloud/prowler/pull/7604) +- Add new check `teams_meeting_external_chat_disabled` [(#7605)](https://github.com/prowler-cloud/prowler/pull/7605) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.metadata.json new file mode 100644 index 0000000000..50c5d8d138 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_external_chat_disabled", + "CheckTitle": "Ensure external meeting chat is off", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure users can't read or write messages in external meeting chats with untrusted organizations.", + "Risk": "Allowing chat in external meetings increases the risk of exploits like GIFShell or DarkGate malware being delivered to users through untrusted organizations.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowExternalNonTrustedMeetingChat $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting engagement set External meeting chat to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable external meeting chat to prevent potential security risks from untrusted organizations. This helps protect against exploits like GIFShell or DarkGate malware.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.py new file mode 100644 index 0000000000..ac4787f7e6 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled.py @@ -0,0 +1,44 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_external_chat_disabled(Check): + """Check if external meeting chat is disabled. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for external meeting chat settings. + + This method checks if external meeting chat is disabled for untrusted organizations. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "External meeting chat is enabled for untrusted organizations." + ) + + if not global_meeting_policy.allow_external_non_trusted_meeting_chat: + report.status = "PASS" + report.status_extended = ( + "External meeting chat is disabled for untrusted organizations." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 1e61f7139a..96027214ff 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -66,6 +66,9 @@ class Teams(M365Service): allow_pstn_users_to_bypass_lobby=global_meeting_policy.get( "AllowPSTNUsersToBypassLobby", True ), + allow_external_non_trusted_meeting_chat=global_meeting_policy.get( + "AllowExternalNonTrustedMeetingChat", True + ), meeting_chat_enabled_type=global_meeting_policy.get( "MeetingChatEnabledType", "EnabledForEveryone" ), @@ -113,6 +116,7 @@ class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_join_meeting: bool = True allow_anonymous_users_to_start_meeting: bool = True allow_external_participant_give_request_control: bool = True + allow_external_non_trusted_meeting_chat: bool = True allow_external_users_to_bypass_lobby: str = "Everyone" allow_pstn_users_to_bypass_lobby: bool = True meeting_chat_enabled_type: str = "EnabledForEveryone" diff --git a/tests/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled_test.py new file mode 100644 index 0000000000..69da25e0eb --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_external_chat_disabled/teams_meeting_external_chat_disabled_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_external_chat_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled import ( + teams_meeting_external_chat_disabled, + ) + + check = teams_meeting_external_chat_disabled() + result = check.execute() + assert len(result) == 0 + + def test_external_chat_enabled(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled import ( + teams_meeting_external_chat_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_non_trusted_meeting_chat=True + ) + + check = teams_meeting_external_chat_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External meeting chat is enabled for untrusted organizations." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_external_chat_disabled(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_external_chat_disabled.teams_meeting_external_chat_disabled import ( + teams_meeting_external_chat_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_external_non_trusted_meeting_chat=False + ) + + check = teams_meeting_external_chat_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External meeting chat is disabled for untrusted organizations." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index 5bf948383d..cb29b864a9 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -29,6 +29,7 @@ def mock_get_global_meeting_policy(_): allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, allow_external_participant_give_request_control=False, + allow_external_non_trusted_meeting_chat=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", @@ -127,6 +128,7 @@ class Test_Teams_Service: allow_anonymous_users_to_join_meeting=False, allow_anonymous_users_to_start_meeting=False, allow_external_participant_give_request_control=False, + allow_external_non_trusted_meeting_chat=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", From 793c2ae9470d2607889070f8a0d306c48a04621d Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Fri, 25 Apr 2025 18:35:54 +0200 Subject: [PATCH 224/359] feat(teams): add new check `teams_meeting_recording_disabled` (#7607) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...s_meeting_recording_disabled.metadata.json | 30 +++++ .../teams_meeting_recording_disabled.py | 40 ++++++ .../m365/services/teams/teams_service.py | 4 + .../teams_meeting_recording_disabled_test.py | 118 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 195 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_recording_disabled/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 5cb5a4b358..0d67370f1a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_dial_in_lobby_bypass_disabled` [(#7571)](https://github.com/prowler-cloud/prowler/pull/7571) - Add new check `teams_meeting_external_control_disabled` [(#7604)](https://github.com/prowler-cloud/prowler/pull/7604) - Add new check `teams_meeting_external_chat_disabled` [(#7605)](https://github.com/prowler-cloud/prowler/pull/7605) +- Add new check `teams_meeting_recording_disabled` [(#7607)](https://github.com/prowler-cloud/prowler/pull/7607) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.metadata.json new file mode 100644 index 0000000000..5ebee7db6e --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_recording_disabled", + "CheckTitle": "Ensure meeting recording is disabled by default", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensures that only authorized users, such as organizers, co-organizers, and leads, can initiate a recording.", + "Risk": "Allowing meeting recordings by default increases the risk of unauthorized individuals capturing and potentially sharing sensitive meeting content.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AllowCloudRecording $false", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under Recording & transcription set Meeting recording to Off.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable meeting recording in the Global meeting policy to ensure only authorized users can initiate recordings. Create separate policies for users or groups who need recording capabilities.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.py b/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.py new file mode 100644 index 0000000000..3da4c89c9c --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled.py @@ -0,0 +1,40 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_recording_disabled(Check): + """Check if meeting recording is disabled by default. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for meeting recording settings. + + This method checks if meeting recording is disabled in the Global meeting policy. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = "Meeting recording is enabled by default." + + if not global_meeting_policy.allow_cloud_recording: + report.status = "PASS" + report.status_extended = "Meeting recording is disabled by default." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 96027214ff..408a44d20e 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -69,6 +69,9 @@ class Teams(M365Service): allow_external_non_trusted_meeting_chat=global_meeting_policy.get( "AllowExternalNonTrustedMeetingChat", True ), + allow_cloud_recording=global_meeting_policy.get( + "AllowCloudRecording", True + ), meeting_chat_enabled_type=global_meeting_policy.get( "MeetingChatEnabledType", "EnabledForEveryone" ), @@ -117,6 +120,7 @@ class GlobalMeetingPolicy(BaseModel): allow_anonymous_users_to_start_meeting: bool = True allow_external_participant_give_request_control: bool = True allow_external_non_trusted_meeting_chat: bool = True + allow_cloud_recording: bool = True allow_external_users_to_bypass_lobby: str = "Everyone" allow_pstn_users_to_bypass_lobby: bool = True meeting_chat_enabled_type: str = "EnabledForEveryone" diff --git a/tests/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled_test.py b/tests/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled_test.py new file mode 100644 index 0000000000..617d9ebc49 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_recording_disabled/teams_meeting_recording_disabled_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_recording_disabled: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled import ( + teams_meeting_recording_disabled, + ) + + check = teams_meeting_recording_disabled() + result = check.execute() + assert len(result) == 0 + + def test_meeting_recording_enabled(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled import ( + teams_meeting_recording_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_cloud_recording=True + ) + + check = teams_meeting_recording_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended == "Meeting recording is enabled by default." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_meeting_recording_disabled(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_recording_disabled.teams_meeting_recording_disabled import ( + teams_meeting_recording_disabled, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + allow_cloud_recording=False + ) + + check = teams_meeting_recording_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended == "Meeting recording is disabled by default." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index cb29b864a9..badb0f74bf 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -30,6 +30,7 @@ def mock_get_global_meeting_policy(_): allow_anonymous_users_to_start_meeting=False, allow_external_participant_give_request_control=False, allow_external_non_trusted_meeting_chat=False, + allow_cloud_recording=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", @@ -129,6 +130,7 @@ class Test_Teams_Service: allow_anonymous_users_to_start_meeting=False, allow_external_participant_give_request_control=False, allow_external_non_trusted_meeting_chat=False, + allow_cloud_recording=False, allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", From ac79b86810cae0f3e98cf33d056d4abd98ed5265 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Fri, 25 Apr 2025 20:34:05 +0200 Subject: [PATCH 225/359] feat(teams): add new check `teams_meeting_presenters_restricted` (#7613) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...eeting_presenters_restricted.metadata.json | 30 +++++ .../teams_meeting_presenters_restricted.py | 47 +++++++ .../m365/services/teams/teams_service.py | 4 + ...eams_meeting_presenters_restricted_test.py | 118 ++++++++++++++++++ .../m365/services/teams/teams_service_test.py | 2 + 7 files changed, 202 insertions(+) create mode 100644 prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/__init__.py create mode 100644 prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.metadata.json create mode 100644 prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.py create mode 100644 tests/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 0d67370f1a..48ad34deea 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. - Add new check `teams_meeting_external_control_disabled` [(#7604)](https://github.com/prowler-cloud/prowler/pull/7604) - Add new check `teams_meeting_external_chat_disabled` [(#7605)](https://github.com/prowler-cloud/prowler/pull/7605) - Add new check `teams_meeting_recording_disabled` [(#7607)](https://github.com/prowler-cloud/prowler/pull/7607) +- Add new check `teams_meeting_presenters_restricted` [(#7613)](https://github.com/prowler-cloud/prowler/pull/7613) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) ### Fixed diff --git a/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/__init__.py b/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.metadata.json b/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.metadata.json new file mode 100644 index 0000000000..d1117d0e2a --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "teams_meeting_presenters_restricted", + "CheckTitle": "Ensure only organizers and co-organizers can present", + "CheckType": [], + "ServiceName": "teams", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Teams Global Meeting Policy", + "Description": "Ensure only organizers and co-organizers can present in a Teams meeting. The recommended state is 'Only organizers and co-organizers'.", + "Risk": "Allowing everyone to present increases the risk that a malicious user can inadvertently show inappropriate content.", + "RelatedUrl": "https://learn.microsoft.com/en-us/microsoftteams/meeting-who-present-request-control", + "Remediation": { + "Code": { + "CLI": "Set-CsTeamsMeetingPolicy -Identity Global -DesignatedPresenterRoleMode \"OrganizerOnlyUserOverride\"", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under content sharing set Who can present to Only organizers and co-organizers.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict presentation capabilities to only organizers and co-organizers to reduce the risk of inappropriate content being shown.", + "Url": "https://learn.microsoft.com/en-us/microsoftteams/meeting-who-present-request-control" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.py b/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.py new file mode 100644 index 0000000000..bfbdd169f2 --- /dev/null +++ b/prowler/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted.py @@ -0,0 +1,47 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.teams.teams_client import teams_client + + +class teams_meeting_presenters_restricted(Check): + """Check if only organizers and co-organizers can present. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for meeting presenter settings. + + This method checks if only organizers and co-organizers can present. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + global_meeting_policy = teams_client.global_meeting_policy + if global_meeting_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=global_meeting_policy if global_meeting_policy else {}, + resource_name="Teams Meetings Global (Org-wide default) Policy", + resource_id="teamsMeetingsGlobalPolicy", + ) + report.status = "FAIL" + report.status_extended = ( + "Not only organizers and co-organizers can present." + ) + + if ( + global_meeting_policy.designated_presenter_role_mode + == "OrganizerOnlyUserOverride" + ): + report.status = "PASS" + report.status_extended = ( + "Only organizers and co-organizers can present." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/teams/teams_service.py b/prowler/providers/m365/services/teams/teams_service.py index 408a44d20e..ad2d7b3721 100644 --- a/prowler/providers/m365/services/teams/teams_service.py +++ b/prowler/providers/m365/services/teams/teams_service.py @@ -72,6 +72,9 @@ class Teams(M365Service): allow_cloud_recording=global_meeting_policy.get( "AllowCloudRecording", True ), + designated_presenter_role_mode=global_meeting_policy.get( + "DesignatedPresenterRoleMode", "EveryoneUserOverride" + ), meeting_chat_enabled_type=global_meeting_policy.get( "MeetingChatEnabledType", "EnabledForEveryone" ), @@ -121,6 +124,7 @@ class GlobalMeetingPolicy(BaseModel): allow_external_participant_give_request_control: bool = True allow_external_non_trusted_meeting_chat: bool = True allow_cloud_recording: bool = True + designated_presenter_role_mode: str = "EveryoneUserOverride" allow_external_users_to_bypass_lobby: str = "Everyone" allow_pstn_users_to_bypass_lobby: bool = True meeting_chat_enabled_type: str = "EnabledForEveryone" diff --git a/tests/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted_test.py b/tests/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted_test.py new file mode 100644 index 0000000000..5c47f1e445 --- /dev/null +++ b/tests/providers/m365/services/teams/teams_meeting_presenters_restricted/teams_meeting_presenters_restricted_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_teams_meeting_presenters_restricted: + def test_no_global_meeting_policy(self): + teams_client = mock.MagicMock() + teams_client.global_meeting_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted import ( + teams_meeting_presenters_restricted, + ) + + check = teams_meeting_presenters_restricted() + result = check.execute() + assert len(result) == 0 + + def test_presenters_not_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted import ( + teams_meeting_presenters_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + designated_presenter_role_mode="EveryoneUserOverride" + ) + + check = teams_meeting_presenters_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Not only organizers and co-organizers can present." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" + + def test_presenters_restricted(self): + teams_client = mock.MagicMock() + teams_client.audited_tenant = "audited_tenant" + teams_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams" + ), + mock.patch( + "prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted.teams_client", + new=teams_client, + ), + ): + from prowler.providers.m365.services.teams.teams_meeting_presenters_restricted.teams_meeting_presenters_restricted import ( + teams_meeting_presenters_restricted, + ) + from prowler.providers.m365.services.teams.teams_service import ( + GlobalMeetingPolicy, + ) + + teams_client.global_meeting_policy = GlobalMeetingPolicy( + designated_presenter_role_mode="OrganizerOnlyUserOverride" + ) + + check = teams_meeting_presenters_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Only organizers and co-organizers can present." + ) + assert result[0].resource == teams_client.global_meeting_policy.dict() + assert ( + result[0].resource_name + == "Teams Meetings Global (Org-wide default) Policy" + ) + assert result[0].resource_id == "teamsMeetingsGlobalPolicy" diff --git a/tests/providers/m365/services/teams/teams_service_test.py b/tests/providers/m365/services/teams/teams_service_test.py index badb0f74bf..a87e51ca33 100644 --- a/tests/providers/m365/services/teams/teams_service_test.py +++ b/tests/providers/m365/services/teams/teams_service_test.py @@ -31,6 +31,7 @@ def mock_get_global_meeting_policy(_): allow_external_participant_give_request_control=False, allow_external_non_trusted_meeting_chat=False, allow_cloud_recording=False, + designated_presenter_role_mode="EveryoneUserOverride", allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", @@ -131,6 +132,7 @@ class Test_Teams_Service: allow_external_participant_give_request_control=False, allow_external_non_trusted_meeting_chat=False, allow_cloud_recording=False, + designated_presenter_role_mode="EveryoneUserOverride", allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests", allow_pstn_users_to_bypass_lobby=False, meeting_chat_enabled_type="EnabledExceptAnonymous", From b8836c6404041d2365b3fc46129cfd993e008c88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 08:49:33 +0200 Subject: [PATCH 226/359] chore(deps): bump @babel/runtime from 7.24.7 to 7.27.0 in /ui (#7502) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 8d222871e0..f0a11642d6 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -240,9 +240,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, From 06f94f884f6f59916a2922efcad427bb8c80d70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 28 Apr 2025 09:57:52 +0200 Subject: [PATCH 227/359] feat(compliance): add new Prowler Threat Score Compliance Framework (#7603) Co-authored-by: MrCloudSec --- .../compliance/prowler_threatscore_aws.py | 24 + .../compliance/prowler_threatscore_azure.py | 24 + .../compliance/prowler_threatscore_gcp.py | 24 + dashboard/pages/compliance.py | 102 +- prowler/CHANGELOG.md | 1 + prowler/__main__.py | 45 + .../aws/prowler_threatscore_aws.json | 1864 +++++++++++++++++ .../azure/prowler_threatscore_azure.json | 1317 ++++++++++++ .../gcp/prowler_threatscore_gcp.json | 977 +++++++++ prowler/lib/check/compliance_models.py | 13 + prowler/lib/outputs/compliance/compliance.py | 12 + .../prowler_threatscore/__init__.py | 0 .../compliance/prowler_threatscore/models.py | 81 + .../prowler_threatscore.py | 121 ++ .../prowler_threatscore_aws.py | 91 + .../prowler_threatscore_azure.py | 91 + .../prowler_threatscore_gcp.py | 91 + prowler_threatscore_aws | 0 prowler_threatscore_azure | 0 prowler_threatscore_gcp | 0 tests/lib/outputs/compliance/fixtures.py | 127 ++ .../prowler_threatscore_aws_test.py | 140 ++ .../prowler_threatscore_azure_test.py | 150 ++ .../prowler_threatscore_gcp_test.py | 147 ++ ...te_compliance_json_from_csv_threatscope.py | 36 + ...prowler_threatscore_from_generic_output.py | 52 + 26 files changed, 5528 insertions(+), 2 deletions(-) create mode 100644 dashboard/compliance/prowler_threatscore_aws.py create mode 100644 dashboard/compliance/prowler_threatscore_azure.py create mode 100644 dashboard/compliance/prowler_threatscore_gcp.py create mode 100644 prowler/compliance/aws/prowler_threatscore_aws.json create mode 100644 prowler/compliance/azure/prowler_threatscore_azure.json create mode 100644 prowler/compliance/gcp/prowler_threatscore_gcp.json create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/__init__.py create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/models.py create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore.py create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws.py create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure.py create mode 100644 prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp.py create mode 100644 prowler_threatscore_aws create mode 100644 prowler_threatscore_azure create mode 100644 prowler_threatscore_gcp create mode 100644 tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws_test.py create mode 100644 tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure_test.py create mode 100644 tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp_test.py create mode 100644 util/generate_compliance_json_from_csv_threatscope.py create mode 100644 util/get_prowler_threatscore_from_generic_output.py diff --git a/dashboard/compliance/prowler_threatscore_aws.py b/dashboard/compliance/prowler_threatscore_aws.py new file mode 100644 index 0000000000..94558f33ad --- /dev/null +++ b/dashboard/compliance/prowler_threatscore_aws.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_cis + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/dashboard/compliance/prowler_threatscore_azure.py b/dashboard/compliance/prowler_threatscore_azure.py new file mode 100644 index 0000000000..94558f33ad --- /dev/null +++ b/dashboard/compliance/prowler_threatscore_azure.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_cis + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/dashboard/compliance/prowler_threatscore_gcp.py b/dashboard/compliance/prowler_threatscore_gcp.py new file mode 100644 index 0000000000..94558f33ad --- /dev/null +++ b/dashboard/compliance/prowler_threatscore_gcp.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_cis + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/dashboard/pages/compliance.py b/dashboard/pages/compliance.py index 422e801503..d9c5c9f4b0 100644 --- a/dashboard/pages/compliance.py +++ b/dashboard/pages/compliance.py @@ -398,6 +398,10 @@ def display_data( f"dashboard.compliance.{current}" ) data.drop_duplicates(keep="first", inplace=True) + + if "threatscore" in analytics_input: + data = get_threatscore_mean_by_pillar(data) + table = compliance_module.get_table(data) except ModuleNotFoundError: table = html.Div( @@ -430,6 +434,9 @@ def display_data( if "pci" in analytics_input: pie_2 = get_bar_graph(df, "REQUIREMENTS_ID") current_filter = "req_id" + elif "threatscore" in analytics_input: + pie_2 = get_table_prowler_threatscore(df) + current_filter = "threatscore" elif ( "REQUIREMENTS_ATTRIBUTES_SECTION" in df.columns and not df["REQUIREMENTS_ATTRIBUTES_SECTION"].isnull().values.any() @@ -488,6 +495,13 @@ def display_data( pie_2, f"Top 5 failed {current_filter} by requirements" ) + if "threatscore" in analytics_input: + security_level_graph = get_graph( + pie_2, + "Pillar Score by requirements (1 = Lowest Risk, 5 = Highest Risk)", + margin_top=0, + ) + return ( table_output, overall_status_result_graph, @@ -501,7 +515,7 @@ def display_data( ) -def get_graph(pie, title): +def get_graph(pie, title, margin_top=7): return [ html.Span( title, @@ -514,7 +528,7 @@ def get_graph(pie, title): "display": "flex", "justify-content": "center", "align-items": "center", - "margin-top": "7%", + "margin-top": f"{margin_top}%", }, ), ] @@ -618,3 +632,87 @@ def get_table(current_compliance, table): className="relative flex flex-col bg-white shadow-provider rounded-xl px-4 py-3 flex-wrap w-full", ), ] + + +def get_threatscore_mean_by_pillar(df): + modified_df = df[df["STATUS"] == "FAIL"] + + modified_df["REQUIREMENTS_ATTRIBUTES_LEVELOFRISK"] = pd.to_numeric( + modified_df["REQUIREMENTS_ATTRIBUTES_LEVELOFRISK"], errors="coerce" + ) + + pillar_means = ( + modified_df.groupby("REQUIREMENTS_ATTRIBUTES_SECTION")[ + "REQUIREMENTS_ATTRIBUTES_LEVELOFRISK" + ] + .mean() + .round(2) + ) + + output = [] + for pillar, mean in pillar_means.items(): + output.append(f"{pillar} - [{mean}]") + + for value in output: + if value.split(" - ")[0] in df["REQUIREMENTS_ATTRIBUTES_SECTION"].values: + df.loc[ + df["REQUIREMENTS_ATTRIBUTES_SECTION"] == value.split(" - ")[0], + "REQUIREMENTS_ATTRIBUTES_SECTION", + ] = value + return df + + +def get_table_prowler_threatscore(df): + df = df[df["STATUS"] == "FAIL"] + + # Delete " - " from the column REQUIREMENTS_ATTRIBUTES_SECTION + df["REQUIREMENTS_ATTRIBUTES_SECTION"] = ( + df["REQUIREMENTS_ATTRIBUTES_SECTION"].str.split(" - ").str[0] + ) + + df["REQUIREMENTS_ATTRIBUTES_LEVELOFRISK"] = pd.to_numeric( + df["REQUIREMENTS_ATTRIBUTES_LEVELOFRISK"], errors="coerce" + ) + + score_df = ( + df.groupby("REQUIREMENTS_ATTRIBUTES_SECTION")[ + "REQUIREMENTS_ATTRIBUTES_LEVELOFRISK" + ] + .mean() + .reset_index() + .rename( + columns={ + "REQUIREMENTS_ATTRIBUTES_SECTION": "Pillar", + "REQUIREMENTS_ATTRIBUTES_LEVELOFRISK": "Score", + } + ) + ) + + fig = px.bar( + score_df, + x="Pillar", + y="Score", + color="Score", + color_continuous_scale=[ + "#45cc6e", + "#f4d44d", + "#e77676", + ], # verde → amarillo → rojo + hover_data={"Score": True, "Pillar": True}, + labels={"Score": "Average Risk Score", "Pillar": "Section"}, + height=400, + ) + + fig.update_layout( + xaxis_title="Pillar", + yaxis_title="Level of Risk", + margin=dict(l=20, r=20, t=30, b=20), + plot_bgcolor="rgba(0,0,0,0)", + paper_bgcolor="rgba(0,0,0,0)", + coloraxis_colorbar=dict(title="Risk"), + ) + + return dcc.Graph( + figure=fig, + style={"height": "25rem", "width": "40rem"}, + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 48ad34deea..51b7e45c7a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -35,6 +35,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_recording_disabled` [(#7607)](https://github.com/prowler-cloud/prowler/pull/7607) - Add new check `teams_meeting_presenters_restricted` [(#7613)](https://github.com/prowler-cloud/prowler/pull/7613) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) +- Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) ### Fixed diff --git a/prowler/__main__.py b/prowler/__main__.py index 13b430e764..b201268da3 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -70,6 +70,15 @@ from prowler.lib.outputs.compliance.mitre_attack.mitre_attack_azure import ( AzureMitreAttack, ) from prowler.lib.outputs.compliance.mitre_attack.mitre_attack_gcp import GCPMitreAttack +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_aws import ( + ProwlerThreatScoreAWS, +) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_azure import ( + ProwlerThreatScoreAzure, +) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_gcp import ( + ProwlerThreatScoreGCP, +) from prowler.lib.outputs.csv.csv import CSV from prowler.lib.outputs.finding import Finding from prowler.lib.outputs.html.html import HTML @@ -478,6 +487,18 @@ def prowler(): ) generated_outputs["compliance"].append(kisa_ismsp) kisa_ismsp.batch_write_data_to_file() + elif compliance_name == "prowler_threatscore_aws": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + prowler_threatscore = ProwlerThreatScoreAWS( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(prowler_threatscore) + prowler_threatscore.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" @@ -545,6 +566,18 @@ def prowler(): ) generated_outputs["compliance"].append(iso27001) iso27001.batch_write_data_to_file() + elif compliance_name == "prowler_threatscore_azure": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + prowler_threatscore = ProwlerThreatScoreAzure( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(prowler_threatscore) + prowler_threatscore.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" @@ -612,6 +645,18 @@ def prowler(): ) generated_outputs["compliance"].append(iso27001) iso27001.batch_write_data_to_file() + elif compliance_name == "prowler_threatscore_gcp": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + prowler_threatscore = ProwlerThreatScoreGCP( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(prowler_threatscore) + prowler_threatscore.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" diff --git a/prowler/compliance/aws/prowler_threatscore_aws.json b/prowler/compliance/aws/prowler_threatscore_aws.json new file mode 100644 index 0000000000..dcc036f7f6 --- /dev/null +++ b/prowler/compliance/aws/prowler_threatscore_aws.json @@ -0,0 +1,1864 @@ +{ + "Framework": "ProwlerThreatScore", + "Version": "1.0", + "Provider": "AWS", + "Description": "Prowler ThreatScore Compliance Framework for AWS ensures that the AWS account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + "Requirements": [ + { + "Id": "1.1.1", + "Description": "Ensure MFA is enabled for the 'root' user account", + "Checks": [ + "iam_root_mfa_enabled" + ], + "Attributes": [ + { + "Title": "MFA enabled for 'root'", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + "AdditionalInformation": "Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.1.2", + "Description": "Ensure hardware MFA is enabled for the 'root' user account", + "Checks": [ + "iam_root_hardware_mfa_enabled" + ], + "Attributes": [ + { + "Title": "Hardware MFA enabled for 'root'", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + "AdditionalInformation": "A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.1.3", + "Description": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have console access", + "Checks": [ + "iam_user_mfa_enabled_console_access" + ], + "Attributes": [ + { + "Title": "MFA enabled for IAM console users", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "To enhance security and reduce the risk of unauthorized access, Multi-Factor Authentication (MFA) should be enabled for all IAM users who have access to the AWS Management Console.", + "AdditionalInformation": "Without Multi-Factor Authentication (MFA), a compromised password alone is enough to allow an attacker to access the console, gaining full visibility and control over AWS resources.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.1.4", + "Description": "Ensure IAM password policy requires minimum length of 14 or greater", + "Checks": [ + "iam_password_policy_minimum_length_14" + ], + "Attributes": [ + { + "Title": "IAM password lenght 14 or greater", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Password policies help enforce password complexity requirements to strengthen account security. In AWS IAM, password policies can be configured to ensure that user passwords meet specific criteria, including a minimum length requirement. It is recommended to enforce a minimum password length of 14 characters to enhance security.", + "AdditionalInformation": "Requiring longer and more complex passwords reduces the risk of compromise from brute force attacks, credential stuffing, and other password-based threats. A 14-character minimum makes it significantly harder for attackers to guess or crack passwords, improving overall account security and resilience.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.5", + "Description": "Ensure IAM password policy prevents password reuse", + "Checks": [ + "iam_password_policy_reuse_24" + ], + "Attributes": [ + { + "Title": "IAM prevent password reuse", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "IAM password policies can be configured to prevent users from reusing previous passwords. This ensures that users create new, unique passwords instead of cycling through old ones. It is recommended to enforce password history restrictions to enhance security.", + "AdditionalInformation": "Blocking password reuse helps mitigate the risk of credential-based attacks, such as brute force and credential stuffing. It prevents users from reverting to previously compromised passwords, reducing the likelihood of unauthorized access.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.6", + "Description": "Ensure IAM password policy require at least one number", + "Checks": [ + "iam_password_policy_number" + ], + "Attributes": [ + { + "Title": "IAM password requires one number or more", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Password policies help enforce password complexity requirements to strengthen account security. In AWS IAM, password policies can be configured to ensure that user passwords meet specific criteria, including using at least number as requirement. It is recommended to enforce the usage of one number to enhance security.", + "AdditionalInformation": "Requiring more complex passwords reduces the risk of compromise from brute force attacks, credential stuffing, and other password-based threats. Using a number at least makes it significantly harder for attackers to guess or crack passwords, improving overall account security and resilience.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.7", + "Description": "Ensure IAM password policy require at least one symbol", + "Checks": [ + "iam_password_policy_symbol" + ], + "Attributes": [ + { + "Title": "IAM password policy require one symbol or more", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "IAM password policies can be configured to enforce the use of at least one special character (symbol) in user passwords. Special characters (e.g., @, #, $, %) add complexity, making passwords harder to guess or crack. It is recommended to require at least one symbol in IAM passwords to enhance security.", + "AdditionalInformation": "Requiring a symbol in passwords increases entropy, making brute-force and dictionary attacks more difficult. Attackers often rely on common or predictable password patterns, and enforcing special characters helps reduce the effectiveness of such attacks. This policy strengthens overall password security and aligns with industry best practices.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.8", + "Description": "Ensure IAM password policy require at least one lowercase letter", + "Checks": [ + "iam_password_policy_lowercase" + ], + "Attributes": [ + { + "Title": "IAM password policy require one lowercase or more", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "IAM password policies can be configured to enforce the use of at least one lowercase letter in user passwords. Including lowercase letters increases password complexity, making them more resistant to brute-force and dictionary attacks. It is recommended to require at least one lowercase letter in IAM passwords to strengthen security.", + "AdditionalInformation": "Requiring at least one lowercase letter ensures that passwords are not composed solely of numbers or uppercase letters, which are easier to guess. Attackers often use wordlists and predictable patterns when attempting to crack passwords. By enforcing lowercase letters, password complexity improves, reducing the likelihood of unauthorized access.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.9", + "Description": "Ensure IAM password policy requires at least one uppercase letter", + "Checks": [ + "iam_password_policy_uppercase" + ], + "Attributes": [ + { + "Title": "IAM password policy require one uppercase or more", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "IAM password policies can be configured to enforce the use of at least one uppercase letter in user passwords. Including uppercase letters increases password complexity, making them more resilient to brute-force and dictionary attacks. It is recommended to require at least one uppercase letter in IAM passwords to enhance security.", + "AdditionalInformation": "Requiring at least one uppercase letter ensures that passwords are not composed solely of lowercase letters or numbers, which are more predictable and easier to crack. Attackers often rely on common word variations in password attacks, and enforcing uppercase letters adds an additional layer of complexity, reducing the risk of unauthorized access.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.10", + "Description": "Ensure credentials unused for 45 days or more are disabled", + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused" + ], + "Attributes": [ + { + "Title": "IAM credentials unused disabled", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "AWS IAM users can authenticate and access AWS resources using various types of credentials, including passwords and access keys. To minimize security risks, it is recommended to deactivate or remove any credentials that have been unused for 45 days or more.", + "AdditionalInformation": "Disabling or removing inactive credentials reduces the attack surface and prevents unauthorized access through compromised or forgotten credentials. Unused credentials pose a security risk, as attackers may exploit them if they remain active without regular monitoring. Regularly auditing and revoking stale credentials enhances overall account security.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.1.11", + "Description": "Ensure access keys are rotated every 90 days or less", + "Checks": [ + "iam_rotate_access_key_90_days" + ], + "Attributes": [ + { + "Title": "IAM rotate access keys 90 days", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Access keys consist of an access key ID and a secret access key, which are used to authenticate and sign programmatic requests made to AWS. These keys allow users and applications to interact with AWS services via the AWS Command Line Interface (CLI), AWS SDKs, PowerShell tools, or direct API calls. To maintain security, it is recommended that all access keys be rotated regularly to minimize the risk of unauthorized access.", + "AdditionalInformation": "Regularly rotating access keys reduces the risk of compromised credentials being exploited. If an access key is leaked, cracked, or stolen, rotating it limits the window of opportunity for malicious use. Additionally, rotating keys ensures that inactive or outdated credentials cannot be used for unauthorized access, enhancing overall security and compliance.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "1.1.12", + "Description": "Ensure credentials unused for 90 days or greater are disabled", + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused" + ], + "Attributes": [ + { + "Title": "Credentials unused for 90 days disabled", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "AWS IAM credentials, such as passwords and access keys, grant access to AWS resources. Credentials that remain unused for 90 days or more pose a security risk, as they may belong to inactive users or forgotten accounts. It is recommended to disable or remove IAM credentials that have not been used for 90 days to reduce the risk of unauthorized access.", + "AdditionalInformation": "Disabling unused credentials minimizes the attack surface by ensuring that inactive or abandoned accounts cannot be exploited by attackers. Stale credentials may become a target for brute-force attacks, credential stuffing, or insider threats. Regularly auditing and deactivating unused credentials helps maintain a least privilege security model, reducing the likelihood of unauthorized access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.1.13", + "Description": "Ensure IAM password policy expires passwords within 90 days or less", + "Checks": [ + "iam_password_policy_expires_passwords_within_90_days_or_less" + ], + "Attributes": [ + { + "Title": "IAM password expires within 90 days", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "IAM password policies can be configured to enforce password expiration after a defined period. It is recommended that passwords be set to expire within 90 days or less to ensure users regularly update their credentials. This helps mitigate security risks associated with stale or compromised passwords that remain active for extended periods.", + "AdditionalInformation": "Requiring password expiration within 90 days or less reduces the risk of credential-based attacks, such as brute-force attacks and credential stuffing, by ensuring that old passwords cannot be used indefinitely. If a password has been exposed or compromised without detection, regular expiration limits the window of opportunity for an attacker to exploit it. This policy enforces stronger access control and aligns with industry security best practices.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "1.1.14", + "Description": "Ensure no root account access key exists", + "Checks": [ + "iam_no_root_access_key" + ], + "Attributes": [ + { + "Title": "No root access key", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "The root account in AWS has unrestricted administrative privileges and should be protected with the highest security measures. Access keys provide programmatic access to AWS, but when linked to the root account, they pose a significant security risk. It is recommended that no access keys be associated with the root account, ensuring that all programmatic access is managed through IAM roles and users with least privilege access.", + "AdditionalInformation": "The root account holds the highest level of privileges in an AWS environment. AWS Access Keys enable programmatic access to AWS resources, but when associated with the root account, they pose a significant security risk. It is recommended to remove all access keys linked to the root account to minimize potential attack vectors. Eliminating root access keys reduces the risk of unauthorized access and enforces the use of role-based IAM accounts with least privilege, promoting a more secure and controlled access management approach.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.1", + "Description": "Ensure IAM policies are attached only to groups or roles", + "Checks": [ + "iam_policy_attached_only_to_group_or_roles" + ], + "Attributes": [ + { + "Title": "IAM policies attached to group or roles", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "IAM policies define permissions that control access to AWS resources. To ensure scalability, security, and manageability, it is recommended that IAM policies be attached only to groups or roles rather than individual users. By assigning permissions at the group or role level, organizations can apply consistent security policies and avoid permission sprawl.", + "AdditionalInformation": "Attaching policies to groups or roles simplifies access control, reduces security risks, and improves compliance tracking. This approach prevents overprivileged accounts and ensures a structured, scalable IAM policy framework.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.2", + "Description": "Ensure IAM users receive permissions only through groups", + "Checks": [ + "iam_policy_attached_only_to_group_or_roles" + ], + "Attributes": [ + { + "Title": "IAM users get permissions through groups", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "IAM users gain access to AWS services, functions, and data through IAM policies. There are four ways to assign policies to a user: 1.Inline (User-Specific) Policy – Editing the policy directly within the user’s profile.2.Directly Attached Policy – Assigning a standalone policy to a user.3.Group-Based Policy (Recommended) – Adding the user to an IAM group with an attached policy. 4.Group with Inline Policy – Assigning an inline policy to a group that includes the user.Among these methods, only the third approach (group-based policies) is recommended for security and manageability.", + "AdditionalInformation": "Managing IAM permissions exclusively through groups ensures consistent, scalable, and role-based access control. This approach reduces the risk of excessive privileges, simplifies auditing, and aligns user permissions with organizational roles.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.1", + "Description": "Ensure IAM policies that allow full *:* administrative privileges are not attached", + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges" + ], + "Attributes": [ + { + "Title": "IAM policies with full privileges not attached", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "IAM policies define permissions for users, groups, and roles, controlling access to AWS resources. Following the principle of least privilege, users should be granted only the permissions necessary to perform their tasks. Instead of assigning broad administrative privileges, permissions should be carefully crafted to allow only the required actions.", + "AdditionalInformation": "Starting with minimal permissions and granting additional access as needed is significantly more secure than providing excessive permissions and attempting to restrict them later. Assigning full administrative privileges increases the risk of unauthorized or accidental actions that could compromise AWS resources. IAM policies containing Effect: Allow, Action: , Resource: should be removed to prevent unrestricted access and enforce security best practices.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.3", + "Description": "Ensure a support role has been created to manage incidents with AWS Support", + "Checks": [ + "iam_support_role_created" + ], + "Attributes": [ + { + "Title": "Support role exists to manage incidents", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "AWS offers a Support Center for incident notification, response, technical support, and customer service assistance. To ensure secure and controlled access, an IAM role should be created with a properly assigned policy, allowing only authorized users to manage incidents with AWS Support.", + "AdditionalInformation": "Implementing least privilege access control ensures that only designated users can interact with AWS Support. Assigning an IAM role with a specific policy limits access to only necessary actions, reducing the risk of unauthorized modifications or exposure of sensitive account information.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.4", + "Description": "Ensure IAM instance roles are used for AWS resource access from instances", + "Checks": [ + "ec2_instance_profile_attached" + ], + "Attributes": [ + { + "Title": "Roles used for resource access from instances", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "AWS instances can access AWS resources either by embedding access keys in API calls or by assigning an IAM role with the necessary permissions. Using IAM roles ensures secure, controlled access without hardcoding credentials.", + "AdditionalInformation": "IAM roles eliminate the risks associated with hardcoded credentials, reducing exposure to external threats. Unlike access keys, which can be used outside AWS if compromised, IAM roles require an attacker to maintain control of an instance to exploit privileges. Additionally, IAM roles simplify credential management by ensuring permissions are automatically updated without the need for manual key rotation.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.3", + "Description": "Ensure that all expired SSL/TLS certificates stored in AWS IAM are removed", + "Checks": [ + "iam_no_expired_server_certificates_stored" + ], + "Attributes": [ + { + "Title": "Expired SSL/TLS certificates removed", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "To enable HTTPS connections for applications and websites hosted on AWS, an SSL/TLS server certificate is required. AWS provides two options for managing certificates: AWS Certificate Manager (ACM) – The preferred method for managing SSL/TLS certificates, automating renewals and deployment. IAM Certificate Storage – Used only when deploying SSL/TLS certificates in regions not supported by ACM. IAM securely encrypts private keys and stores them, but certificates must be obtained from an external provider. ACM certificates cannot be uploaded to IAM, and IAM certificates cannot be managed from the IAM Console.", + "AdditionalInformation": "Removing expired SSL/TLS certificates prevents the accidental deployment of invalid certificates, which could cause service disruptions, security warnings, and loss of credibility for applications using AWS services like Elastic Load Balancer (ELB). As a best practice, expired certificates should be deleted to maintain a secure and trusted application environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.5", + "Description": "Avoid the use of the 'root' account", + "Checks": [ + "iam_avoid_root_usage" + ], + "Attributes": [ + { + "Title": "Don't use root account", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "The root account in AWS has unrestricted administrative privileges and should be used only for initial account setup and emergency scenarios. Regular operations should be performed using IAM users or roles with least privilege access to minimize security risks.", + "AdditionalInformation": "Using the root account increases the risk of unauthorized access, accidental misconfigurations, and privilege misuse. By restricting root account usage and delegating tasks to IAM users or roles, organizations can enforce better access control, auditing, and security best practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.6", + "Description": "Ensure that IAM Access Analyzer is enabled for all regions", + "Checks": [ + "accessanalyzer_enabled" + ], + "Attributes": [ + { + "Title": "Access Analyzer enabled", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Enable IAM Access Analyzer for all AWS regions to monitor IAM policies and identify resources with unintended external access. IAM Access Analyzer, introduced at AWS re:Invent 2019, scans resource-based policies and provides visibility into which resources—such as KMS keys, IAM roles, S3 buckets, Lambda functions, and SQS queues—are accessible by external accounts or federated users. This allows administrators to enforce least privilege access and mitigate unauthorized access risks. IAM Access Analyzer operates within the same AWS region as the resources being analyzed.", + "AdditionalInformation": "IAM Access Analyzer enhances security visibility by detecting AWS resources shared with external entities, helping organizations identify potential security risks and ensure compliance with least privilege principles. It continuously evaluates resource-based policies using logic-based analysis, allowing teams to promptly remediate misconfigurations that could lead to unauthorized access or data exposure.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.7", + "Description": "Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments", + "Checks": [ + "iam_check_saml_providers_sts" + ], + "Attributes": [ + { + "Title": "IAM users managed centrally or by organizations", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "In multi-account AWS environments, centralizing IAM user management improves control, security, and access management efficiency. Instead of creating separate IAM users in each account, access should be managed through role assumption. This can be achieved using AWS Organizations or federation with an external identity provider (e.g., AWS IAM Identity Center, Okta, or Active Directory).", + "AdditionalInformation": "Centralizing IAM user management into a single identity store simplifies administration, reduces the risk of access misconfigurations, and enforces consistent security policies across all accounts. This approach enhances security, scalability, and compliance while minimizing user duplication and permission errors.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.2", + "Description": "Ensure access to AWSCloudShellFullAccess is restricted", + "Checks": [ + "iam_policy_cloudshell_admin_not_attached" + ], + "Attributes": [ + { + "Title": "AWSCloudShellFullAccess restricted", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "AWS CloudShell provides a managed command-line interface (CLI) for interacting with AWS services. The AWSCloudShellFullAccess IAM policy grants full access to CloudShell, including file upload and download capabilities between a user’s local system and the CloudShell environment. Within CloudShell, users have sudo privileges and unrestricted internet access, making it possible to install software—such as file transfer tools—that could facilitate data movement to external servers.", + "AdditionalInformation": "Access to AWSCloudShellFullAccess should be restricted, as it can serve as a potential data exfiltration vector for malicious or compromised cloud administrators. Granting full permissions to CloudShell increases the risk of unauthorized data transfers outside the AWS environment. AWS provides guidance on creating more restrictive IAM policies to limit file transfer capabilities, reducing security risks.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.3", + "Description": "Ensure no IAM Inline policies allow actions that may lead into Privilege Escalation", + "Checks": [ + "iam_inline_policy_allows_privilege_escalation" + ], + "Attributes": [ + { + "Title": "IAM policy allow privilege escalation", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "IAM inline policies define permissions directly attached to users, groups, or roles, rather than being managed as standalone policies. If improperly configured, these policies can grant actions that enable privilege escalation, allowing users to elevate their access beyond intended permissions. Privilege escalation can occur through misconfigured IAM roles, excessive permissions, or indirect access paths, potentially leading to unauthorized control over AWS resources.", + "AdditionalInformation": "Users with some IAM permissions are allowed to elevate their privileges up to administrator rights.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "4.1.1", + "Description": "Ensure S3 Bucket Policy is set to deny HTTP requests", + "Checks": [ + "s3_bucket_secure_transport_policy" + ], + "Attributes": [ + { + "Title": "S3 bucket deny HTTP requests", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Amazon S3 bucket permissions can be configured using a bucket policy to enforce access restrictions. To enhance security, objects within the bucket should be made accessible only via HTTPS, ensuring encrypted data transmission.", + "AdditionalInformation": "By default, Amazon S3 accepts both HTTP and HTTPS requests, which can expose data to interception. To enforce secure access, HTTP requests should be explicitly denied in the bucket policy. Simply allowing HTTPS without blocking HTTP does not fully comply with security best practices, as unencrypted requests may still be accepted.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.2", + "Description": "Ensure that EC2 Metadata Service only allows IMDSv2", + "Checks": [ + "ec2_instance_imdsv2_enabled" + ], + "Attributes": [ + { + "Title": "EC2 Metadata Service only allows IMDSv2", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "AWS EC2 instances allow users to choose between Instance Metadata Service Version 1 (IMDSv1), which uses a request/response model, or Instance Metadata Service Version 2 (IMDSv2), which uses a session-based approach for enhanced security", + "AdditionalInformation": "Instance metadata refers to the data about an EC2 instance, such as host names, events, and security groups, that is used for managing and configuring the instance. When enabling the Metadata Service, users can opt for either IMDSv1, which operates via a simple request/response model, or IMDSv2, which implements session authentication for additional security. With IMDSv2, each request is secured by session-based authentication, ensuring that all interactions with the instance's metadata and credentials are protected. IMDSv1, on the other hand, may expose instances to Server-Side Request Forgery (SSRF) attacks. To improve security, Amazon recommends using IMDSv2", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.1", + "Description": "Ensure MFA Delete is enabled on S3 buckets", + "Checks": [ + "s3_bucket_no_mfa_delete" + ], + "Attributes": [ + { + "Title": "MFA delete enabled on S3 buckets", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Enabling MFA Delete on a sensitive or classified Amazon S3 bucket adds an extra layer of protection by requiring two-factor authentication for critical actions, such as deleting object versions or changing the bucket’s versioning state.", + "AdditionalInformation": "MFA Delete helps prevent accidental or malicious deletions by requiring an additional authentication step. This mitigates the risk of data loss due to compromised credentials or unauthorized access, ensuring that critical objects remain protected.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.2", + "Description": "Ensure all data in Amazon S3 has been discovered, classified, and secured when necessary", + "Checks": [ + "macie_is_enabled" + ], + "Attributes": [ + { + "Title": "Macie enabled", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon S3 buckets may store sensitive data that needs to be discovered, classified, monitored, and protected to maintain security and compliance. Amazon Macie, along with third-party tools, can automatically inventory S3 buckets and identify sensitive data at scale.", + "AdditionalInformation": "Using automated data discovery and classification tools, such as Amazon Macie, enhances security by continuously monitoring S3 buckets for sensitive information. Macie leverages machine learning and pattern matching to detect and protect critical data, reducing the risk of data leaks and unauthorized access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.1", + "Description": "Ensure the default security group of every VPC restricts all traffic", + "Checks": [ + "ec2_securitygroup_default_restrict_traffic" + ], + "Attributes": [ + { + "Title": "Default SG of VPC restrict all traffic", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Each Amazon VPC includes a default security group that initially denies all inbound traffic, allows all outbound traffic, and permits unrestricted communication between instances within the group. If no security group is specified when launching an instance, it is automatically assigned to this default security group. Since security groups control stateful ingress and egress traffic, it is recommended to restrict all inbound and outbound traffic in the default security group.", + "AdditionalInformation": "Restricting all traffic in the default security group enforces least privilege access by ensuring that AWS resources are explicitly assigned to well-defined security groups. This approach reduces unintended exposure, improves network segmentation, and promotes secure resource placement within AWS environments.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "2.1.2", + "Description": "Ensure routing tables for VPC peering are least access", + "Checks": [ + "vpc_peering_routing_tables_with_least_privilege" + ], + "Attributes": [ + { + "Title": "Routing tables for VPC least access", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "After establishing a VPC peering connection, routing tables must be updated to enable communication between the peered VPCs. Routes can be configured with granular specificity, allowing connections to be restricted to a single host or a specific subnet within the peered VPC.", + "AdditionalInformation": "Defining highly specific routes in VPC peering connections enhances security by limiting access to only the necessary resources. This minimizes the potential impact of a security breach, ensuring that resources outside the defined routes remain inaccessible, reducing the risk of lateral movement within the network.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.3", + "Description": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports", + "Checks": [ + "ec2_networkacl_allow_ingress_any_port", + "ec2_networkacl_allow_ingress_tcp_port_22", + "ec2_networkacl_allow_ingress_tcp_port_3389" + ], + "Attributes": [ + { + "Title": "No Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Network Access Control Lists (NACLs) provide stateless filtering of ingress and egress traffic to AWS resources. It is recommended that NACLs do not allow unrestricted inbound access to remote administration ports, such as SSH (port 22) and RDP (port 3389), over TCP (6), UDP (17), or ALL (-1) protocols to prevent unauthorized access.", + "AdditionalInformation": "Exposing remote server administration ports (e.g., SSH on 22 and RDP on 3389) to the public internet increases the attack surface, making resources more vulnerable to brute-force attacks and unauthorized access. Restricting inbound access to these ports helps reduce security risks and limit potential exploitation.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.4", + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports", + "Checks": [ + "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389" + ], + "Attributes": [ + { + "Title": "No SG allow ingress from 0.0.0.0/0 to remote server administration ports", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Security groups enforce stateful filtering of ingress and egress traffic to AWS resources. To enhance security, no security group should allow unrestricted inbound access to remote administration ports, such as SSH (port 22) and RDP (port 3389), over TCP (6), UDP (17), or ALL (-1) protocols.", + "AdditionalInformation": "Exposing remote administration ports to the public internet significantly increases the attack surface, making resources more vulnerable to brute-force attacks, exploitation, and unauthorized access. Restricting ingress traffic to these ports helps reduce security risks and prevent potential system compromises.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "2.2.3", + "Description": "Ensure EBS snapshots are not publicly accessible", + "Checks": [ + "ec2_ebs_public_snapshot" + ], + "Attributes": [ + { + "Title": "EBS snapshots nor publicy accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Elastic Block Store (EBS) snapshots contain backups of EC2 volumes, which may include sensitive data such as credentials, application configurations, or customer information. EBS snapshots should never be publicly accessible to prevent unauthorized access and data exposure. By default, snapshots are private, but they can be manually shared with other AWS accounts or made public, which poses a significant security risk if misconfigured.", + "AdditionalInformation": "Exposing EBS snapshots publicly increases the risk of data breaches, unauthorized access, and compliance violations. Attackers can scan for publicly accessible snapshots and extract sensitive information. To prevent data leaks, snapshots should be restricted to specific AWS accounts or kept private unless explicitly needed for sharing. Implementing proper access controls helps protect critical data and maintain compliance with security best practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.2.1", + "Description": "Ensure EBS volume encryption is enabled in all regions", + "Checks": [ + "ec2_ebs_volume_encryption" + ], + "Attributes": [ + { + "Title": "EBS volume encryption", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Amazon Elastic Compute Cloud (EC2) supports encryption at rest for Elastic Block Store (EBS) volumes, ensuring that stored data remains protected. While EBS encryption is disabled by default, organizations can enforce automatic encryption of newly created volumes to enhance data security and compliance.", + "AdditionalInformation": "Enforcing EBS volume encryption reduces the risk of data exposure, unauthorized access, and compliance violations. If encryption remains intact, even if storage is compromised, data remains unreadable to unauthorized users. Encrypting data at rest ensures that sensitive information is protected against accidental disclosure, insider threats, and external attacks.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "4.2.2", + "Description": "Ensure that encryption-at-rest is enabled for RDS instances", + "Checks": [ + "rds_instance_storage_encrypted" + ], + "Attributes": [ + { + "Title": "RDS instances encryption at rest enabled", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Amazon Relational Database Service (RDS) supports encryption at rest using the industry-standard AES-256 encryption algorithm to secure database instances and their associated storage. Once enabled, RDS encryption automatically handles access authentication and decryption, ensuring secure data storage with minimal performance impact.", + "AdditionalInformation": "Databases often contain sensitive and business-critical information, making encryption essential to protect against unauthorized access and data breaches. Enabling RDS encryption ensures that underlying storage, automated backups, read replicas, and snapshots are all encrypted, preventing accidental or malicious data exposure while maintaining compliance with security best practices.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.3.1", + "Description": "Ensure SNS topics do not allow global send or subscribe", + "Checks": [ + "sns_topics_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "SNS topics do not allow global send or subscribe", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Simple Notification Service (SNS) topics enable messaging between AWS services, applications, and users. By default, SNS topics should be restricted to trusted AWS accounts or IAM roles to prevent unauthorized access. Allowing global send (sns:Publish) or subscribe (sns:Subscribe) permissions means any AWS account or unauthenticated entity could send messages or subscribe to the topic, potentially leading to spam, data leaks, or misuse of notifications.", + "AdditionalInformation": "SNS topics with global send or subscribe permissions expose AWS environments to unauthorized message injection, data exfiltration, and Denial-of-Service (DoS) attacks. An attacker could flood an SNS topic with malicious or fraudulent messages, leading to unexpected charges or service disruptions. Restricting access ensures that only authorized AWS accounts, applications, or IAM roles can send and receive messages, reducing security risks and protecting system integrity.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.4", + "Description": "Ensure RDS snapshots are not publicly accessible", + "Checks": [ + "rds_instance_no_public_access" + ], + "Attributes": [ + { + "Title": "RDS snapshots not publicy accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Relational Database Service (RDS) snapshots store backups of database instances, potentially containing sensitive data such as customer records, credentials, and application configurations. By default, RDS snapshots are private, but they can be shared with other AWS accounts or made public, which can lead to data exposure if misconfigured. To prevent unauthorized access, RDS snapshots should never be publicly accessible unless explicitly required and secured.", + "AdditionalInformation": "Publicly accessible RDS snapshots create a serious security risk, as anyone can copy the snapshot and restore the database, exposing sensitive information. Attackers actively scan for publicly available snapshots to extract credentials, personally identifiable information (PII), or business-critical data. To prevent unauthorized access and data leaks, RDS snapshots should remain private or restricted to trusted AWS accounts following the principle of least privilege.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.5", + "Description": "Ensure the S3 bucket CloudTrail logs is not publicly accessible", + "Checks": [ + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "S3 bucket CloudTrail logs is not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "AWS CloudTrail logs record account activity, including API calls, user actions, and resource modifications, making them critical for security monitoring and compliance auditing. These logs are typically stored in an Amazon S3 bucket for long-term retention and analysis. To protect sensitive security data, the S3 bucket storing CloudTrail logs should never be publicly accessible.", + "AdditionalInformation": "If the S3 bucket containing CloudTrail logs is publicly accessible, unauthorized users could access sensitive security information, including API calls, IAM activity, and infrastructure changes. Exposing CloudTrail logs can help attackers reconstruct system activity, identify vulnerabilities, and plan targeted attacks. To prevent data leaks and unauthorized access, CloudTrail log buckets should be restricted using IAM policies, bucket policies, and S3 Block Public Access settings.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.6", + "Description": "Ensure Redshift clusters do not have a public endpoint", + "Checks": [ + "redshift_cluster_public_access" + ], + "Attributes": [ + { + "Title": "Redshift clusters dont have a public endpoint", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Redshift clusters store and process large-scale data for analytics and business intelligence workloads. By default, Redshift clusters can be configured with a public endpoint, making them accessible from the internet. To minimize security risks, Redshift clusters should be restricted to private networks and should not have a public endpoint unless absolutely necessary and properly secured.", + "AdditionalInformation": "Exposing a Redshift cluster to the public internet increases the risk of unauthorized access, data breaches, and cyberattacks. Attackers could attempt brute-force login attempts, exploit misconfigurations, or access sensitive business data. Keeping Redshift clusters within private subnets and restricting access via security groups, VPC settings, and IAM policies ensures that only trusted networks and users can connect, reducing the attack surface and enhancing data security.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.5", + "Description": "Ensure ApiGateway endpoint is not public", + "Checks": [ + "apigateway_restapi_public" + ], + "Attributes": [ + { + "Title": "ApiGateway endpoint is public", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "AWS API Gateway allows developers to create, deploy, and manage APIs that connect applications to backend services. By default, API Gateway endpoints can be publicly accessible, meaning they can be invoked from anywhere on the internet. To enhance security, API Gateway endpoints should be restricted to private networks using VPC links, private API settings, or access control mechanisms to ensure that only authorized entities can interact with the API.", + "AdditionalInformation": "Publicly accessible API Gateway endpoints can expose backend services to unauthorized access, data leaks, and potential exploitation. Attackers may attempt brute-force authentication, injection attacks, or abuse API functionality if access is not properly restricted. To reduce the attack surface, API Gateway endpoints should be limited to internal use or protected with authentication, IAM permissions, WAF rules, or private VPC access to ensure only trusted users and systems can invoke the API.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.2", + "Description": "Ensure that amazon EC2 instances launched using Auto Scaling group launch configurations do not have Public IP addresses", + "Checks": [ + "autoscaling_group_launch_configuration_no_public_ip" + ], + "Attributes": [ + { + "Title": "EC2 instances launched using autoscaling group launch configurations do not have Public IP addresses", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon EC2 instances launched via Auto Scaling groups can automatically scale workloads based on demand. By default, instances can be assigned public IP addresses, making them accessible from the internet. To enhance security, EC2 instances in Auto Scaling group launch configurations should not have public IP addresses, ensuring they remain within a private network and are only accessible through secure channels such as bastion hosts or VPN connections.", + "AdditionalInformation": "Assigning public IP addresses to Auto Scaling group instances increases the risk of unauthorized access, brute-force attacks, and potential exploitation. Publicly accessible instances can become targets for malicious actors, leading to data breaches or service disruptions. By restricting public IP addresses, organizations can enforce network segmentation, ensuring that EC2 instances are accessed securely via private networks, VPNs, or load balancers.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.3", + "Description": "Ensure that lambda functions have not resource-based policy set as Public", + "Checks": [ + "awslambda_function_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "Lambda functions have not resource-based policy set as Public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Lambda functions allow running code without managing servers. Lambda supports resource-based policies that define who can invoke the function. If a Lambda function’s resource-based policy allows public access, it can be triggered by anyone on the internet, posing a significant security risk. To prevent unauthorized execution, Lambda functions should not be publicly accessible unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible Lambda functions can be abused for unauthorized execution, leading to service disruptions, data exfiltration, or increased AWS costs due to excessive invocations. Attackers could exploit misconfigured functions to perform malicious actions, extract sensitive data, or abuse compute resources. To reduce security risks, Lambda functions should only be accessible to specific IAM roles, AWS services, or trusted accounts, enforcing least privilege access and maintaining secure function execution.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.4", + "Description": "Ensure that Lambda have not public URL Function", + "Checks": [ + "awslambda_function_url_public" + ], + "Attributes": [ + { + "Title": "Lambda have not public URL Function", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Lambda function URLs provide a built-in HTTPS endpoint that allows functions to be invoked directly via HTTP requests. By default, Lambda function URLs can be publicly accessible, meaning anyone on the internet can invoke the function if proper access controls are not enforced. To minimize security risks, Lambda function URLs should not be publicly accessible unless explicitly required and properly restricted.", + "AdditionalInformation": "Exposing Lambda function URLs to the public internet increases the risk of unauthorized access, API abuse, and potential exploitation. Attackers may invoke functions maliciously, leading to data leaks, unauthorized operations, increased costs, or denial-of-service (DoS) attacks. To enhance security, Lambda function URLs should be restricted to specific IAM roles, AWS services, or trusted clients, ensuring that only authorized users can trigger the function.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.5", + "Description": "Ensure DMS instances are not publicly accessible", + "Checks": [ + "dms_instance_no_public_access" + ], + "Attributes": [ + { + "Title": "DMS instances are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Database Migration Service (DMS) instances facilitate data migration between databases across on-premises and cloud environments. By default, DMS instances can be configured with publicly accessible endpoints, making them reachable from the internet. To enhance security and prevent unauthorized access, DMS instances should not be publicly accessible unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible DMS instances increase the risk of unauthorized access, data interception, and potential exploitation. Attackers could target exposed instances to steal or manipulate sensitive data during migration. Restricting public access ensures data migrations remain secure, limiting access to trusted networks, private VPCs, and authorized IAM roles, thereby reducing the attack surface and ensuring compliance with security best practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.7", + "Description": "Ensure DocumentDB manual cluster snapshot is not public", + "Checks": [ + "documentdb_cluster_public_snapshot" + ], + "Attributes": [ + { + "Title": "DocumentDB manual cluster snapshot is not public", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "AWS DocumentDB manual cluster snapshots store backups of DocumentDB clusters, containing sensitive database information such as application data, configurations, and credentials. By default, snapshots are private, but they can be manually shared or made public, which poses a significant security risk. To prevent unauthorized access, DocumentDB manual cluster snapshots should never be publicly accessible unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible DocumentDB snapshots expose critical database information, increasing the risk of data breaches, unauthorized access, and compliance violations. Attackers could restore the snapshot in their own AWS account and gain full access to the database content. To protect sensitive data, DocumentDB snapshots should only be shared with specific AWS accounts or remain private, following least privilege principles and AWS security best practices.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.6", + "Description": "Ensure there are no EC2 AMIs set as Public", + "Checks": [ + "ec2_ami_public" + ], + "Attributes": [ + { + "Title": "No EC2 AMIs set as Public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon EC2 Amazon Machine Images (AMIs) contain pre-configured operating system and application environments that can be used to launch new EC2 instances. By default, AMIs are private, but they can be manually shared or made public, which poses a security risk if sensitive data or proprietary configurations are exposed. To prevent unauthorized access and data leaks, EC2 AMIs should not be set as public unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible EC2 AMIs increase the risk of data exposure, unauthorized access, and compliance violations. Attackers could copy, analyze, or exploit public AMIs to extract sensitive credentials, misconfigurations, or proprietary software. Keeping AMIs private or shared only with specific AWS accounts ensures that only trusted users or teams can access and launch instances from them, reducing security risks and preventing unintended data exposure.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.8", + "Description": "Ensure that public access to EBS snapshots is disabled", + "Checks": [ + "ec2_ebs_snapshot_account_block_public_access" + ], + "Attributes": [ + { + "Title": "Public access to EBS snapshots is disabled", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Elastic Block Store (EBS) snapshots are backups of EC2 volumes that may contain sensitive data, such as credentials, application configurations, and customer records. By default, EBS snapshots are private, but they can be manually shared or made public, allowing anyone to copy or restore them. To prevent unauthorized access and data exposure, public access to EBS snapshots should always be disabled.", + "AdditionalInformation": "Publicly accessible EBS snapshots pose a significant security risk, as attackers can restore and extract sensitive data if a snapshot is exposed. Misconfigured public snapshots have led to data breaches and compliance violations in the past. To mitigate this risk, EBS snapshots should be kept private or explicitly shared only with trusted AWS accounts, following least privilege principles to protect critical data and maintain security compliance.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.6", + "Description": "Ensure that ec2 common ports from instances are not internet-exposed", + "Checks": [ + "ec2_instance_port_cassandra_exposed_to_internet", + "ec2_instance_port_cifs_exposed_to_internet", + "ec2_instance_port_elasticsearch_kibana_exposed_to_internet", + "ec2_instance_port_ftp_exposed_to_internet", + "ec2_instance_port_kafka_exposed_to_internet", + "ec2_instance_port_kerberos_exposed_to_internet", + "ec2_instance_port_ldap_exposed_to_internet", + "ec2_instance_port_memcached_exposed_to_internet", + "ec2_instance_port_mongodb_exposed_to_internet", + "ec2_instance_port_mysql_exposed_to_internet", + "ec2_instance_port_oracle_exposed_to_internet", + "ec2_instance_port_postgresql_exposed_to_internet", + "ec2_instance_port_rdp_exposed_to_internet", + "ec2_instance_port_redis_exposed_to_internet", + "ec2_instance_port_sqlserver_exposed_to_internet", + "ec2_instance_port_ssh_exposed_to_internet", + "ec2_instance_port_telnet_exposed_to_internet" + ], + "Attributes": [ + { + "Title": "Common ports from instances are not exposed", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Amazon EC2 instances can run various services that communicate over common ports such as 22 (SSH), 3389 (RDP), 80 (HTTP), and 443 (HTTPS) (and more). If these ports are open to the internet, attackers can attempt unauthorized access, brute-force attacks, or exploit known vulnerabilities. To reduce security risks, EC2 instances should be configured so that common ports are not exposed to the public internet, unless explicitly required and properly secured.", + "AdditionalInformation": "Exposing common ports directly to the internet increases the attack surface and risks unauthorized access or system compromise. Attackers frequently scan for open ports to target misconfigured or unpatched services. To enhance security, access to EC2 common ports should be restricted using security groups, network ACLs, and VPC configurations, ensuring that only trusted networks and users can connect.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.7", + "Description": "Ensure that ec2 security groups do not allow ingress from internet to common ports", + "Checks": [ + "ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports", + "ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23" + ], + "Attributes": [ + { + "Title": "Common ports from security groups do not allow ingress traffic", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Amazon EC2 security groups act as virtual firewalls, controlling inbound and outbound traffic to instances. If a security group allows ingress (incoming traffic) from the internet (0.0.0.0/0 or ::/0) to common ports such as 22 (SSH), 3389 (RDP), 80 (HTTP), or 443 (HTTPS) (and more), it creates a significant security risk. To minimize exposure, security groups should be configured to restrict ingress access to these ports to only trusted IP addresses or internal networks.", + "AdditionalInformation": "Allowing unrestricted inbound traffic to common ports increases the risk of brute-force attacks, unauthorized access, and exploitation of vulnerabilities. Attackers actively scan for open ports on public-facing EC2 instances to gain unauthorized control. To reduce security risks, ingress rules should be restricted using least privilege principles, IP whitelisting, VPN access, or bastion hosts, ensuring that only authorized users and networks can connect.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "2.3.7", + "Description": "Ensure there are no ECR repositories set as Public", + "Checks": [ + "ecr_repositories_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "No ECR repositories set as Public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic Container Registry (ECR) repositories store and manage container images for deployment in AWS services. By default, ECR repositories are private, but they can be manually configured as public, allowing anyone to pull container images. To prevent unauthorized access and potential security risks, ECR repositories should not be set as public unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible ECR repositories expose container images to unauthorized users, increasing the risk of intellectual property theft, malware injection, or unauthorized use of containerized applications. Attackers could analyze public images for vulnerabilities or use misconfigured images for malicious purposes. To mitigate this risk, ECR repositories should remain private or be explicitly shared with trusted AWS accounts, ensuring secure access and compliance with best practices.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.8", + "Description": "Ensure ECS services do not assign public IPs automatically", + "Checks": [ + "ecs_service_no_assign_public_ip" + ], + "Attributes": [ + { + "Title": "No ECS services assign public IPs automatically", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic Container Service (ECS) allows running containerized applications on AWS. By default, ECS services can be configured to assign public IP addresses to tasks or services, making them directly accessible from the internet. To enhance security, ECS services should be configured not to automatically assign public IPs, ensuring they remain within a private network and are accessed securely through internal load balancers, VPC peering, or private endpoints.", + "AdditionalInformation": "Automatically assigning public IPs to ECS services exposes them to the internet, increasing the risk of unauthorized access, brute-force attacks, and data breaches. Attackers could target publicly exposed containers, exploit vulnerabilities, or disrupt services. To mitigate these risks, ECS services should be restricted to private subnets and accessed through secure networking configurations, such as AWS PrivateLink, VPNs, or internal ALBs.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.9", + "Description": "Ensure ECS task sets do not automatically assign public IP addresses", + "Checks": [ + "ecs_task_set_no_assign_public_ip" + ], + "Attributes": [ + { + "Title": "No ECS tasks sets assign public IPs autocatically", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic Container Service (ECS) task sets manage multiple versions of a service during deployments. By default, ECS task sets can be configured to automatically assign public IP addresses, making them directly accessible from the internet. To enhance security, ECS task sets should be restricted to private subnets and should not automatically receive public IP addresses unless explicitly required and properly secured.", + "AdditionalInformation": "Automatically assigning public IPs to ECS task sets increases the risk of unauthorized access, cyberattacks, and data exposure. Publicly exposed tasks can be targeted by attackers, leading to service disruptions or exploitation of vulnerabilities. To mitigate these risks, ECS task sets should be restricted to private networking environments, accessed only through internal load balancers, VPC endpoints, or secure VPN connections, ensuring controlled and secure communication.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.9", + "Description": "Ensure EFS mount targets are not publicly accessible", + "Checks": [ + "efs_mount_target_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "No EFS mount targets are publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Elastic File System (EFS) provides scalable, shared file storage for AWS services. EFS mount targets allow instances to connect to the file system within a VPC. By default, EFS mount targets can be configured with public accessibility, making them reachable from the internet. To enhance security, EFS mount targets should be restricted to private networks and should not be publicly accessible unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible EFS mount targets expose stored data to unauthorized access, cyberattacks, and data breaches. Attackers could exploit misconfigured security groups or network ACLs to access or modify files. To reduce security risks, EFS mount targets should be restricted to private subnets, with access limited to trusted VPCs, security groups, and IAM roles, ensuring secure file storage and controlled access.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.10", + "Description": "Ensure that EFS do not have policies which allow access to any client within the VPC", + "Checks": [ + "efs_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "No EFS have policies which allow access to any client within the VPC", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon Elastic File System (EFS) provides shared storage that can be accessed by multiple EC2 instances and services within a VPC. EFS access is controlled through resource-based policies that define which clients can connect. If an EFS policy allows access to any client within the VPC, it increases the risk of unauthorized access and data exposure. To enhance security, EFS policies should be restricted to specific IAM roles, security groups, or trusted resources instead of granting broad access to all VPC clients.", + "AdditionalInformation": "Allowing any client within a VPC to access an EFS file system increases the risk of data leaks, accidental modifications, or unauthorized access by compromised instances or misconfigured services. To minimize exposure, EFS policies should enforce least privilege access, restricting permissions to specific instances, roles, or users that require access, ensuring secure file storage and controlled data access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.8", + "Description": "Ensure EKS cluster Network Policy is Enabled and Set as Appropriate", + "Checks": [ + "eks_cluster_network_policy_enabled" + ], + "Attributes": [ + { + "Title": "EKS cluster Network Policy is Enabled and Set as Appropriate", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "A Network Policy defines how network traffic is controlled and restricted between workloads within a cloud environment. Enforcing network policies ensures that only authorized communication occurs between services, reducing the risk of unauthorized access and lateral movement. It is recommended to enable Network Policies and configure them appropriately to enforce least privilege access and secure communication between workloads.", + "AdditionalInformation": "Without properly configured Network Policies, workloads may be exposed to unnecessary or unauthorized network traffic, increasing the risk of data leaks, exploitation, or lateral movement by attackers. By enabling and enforcing Network Policies, organizations can limit communication between workloads, ensuring that only approved and necessary network interactions are allowed, minimizing the attack surface and enhancing overall security.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.9", + "Description": "Ensure EKS Clusters are not publicly accessible", + "Checks": [ + "eks_cluster_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "EKS Clusters are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Amazon Elastic Kubernetes Service (EKS) clusters manage containerized applications and can be configured with either private or public access. If an EKS cluster is publicly accessible, it means that the Kubernetes API endpoint can be reached from the internet, increasing the risk of unauthorized access and attacks. To enhance security, EKS clusters should be restricted to private networks and accessed only through secure VPNs, VPC peering, or AWS PrivateLink.", + "AdditionalInformation": "Exposing an EKS cluster to the public internet increases the risk of brute-force attacks, credential theft, and unauthorized access to Kubernetes workloads. Attackers could exploit misconfigured RBAC policies or API vulnerabilities to gain control over the cluster. To reduce security risks, EKS clusters should be configured with private endpoints, ensuring that only trusted networks and IAM-authenticated users can manage Kubernetes resources.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.1.10", + "Description": "Ensure EKS Clusters are created with Private Nodes", + "Checks": [ + "eks_cluster_private_nodes_enabled" + ], + "Attributes": [ + { + "Title": "EKS Clusters are created with Private Nodes", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Amazon Elastic Kubernetes Service (EKS) clusters run workloads on worker nodes, which can be either public or private. If EKS clusters are created with public nodes, these nodes are assigned public IP addresses, making them accessible from the internet, which increases the risk of unauthorized access and potential attacks. To enhance security, EKS clusters should be created with private nodes that operate within private subnets and are only accessible through secured networking configurations such as VPNs, VPC peering, or AWS PrivateLink.", + "AdditionalInformation": "Using public nodes in EKS exposes Kubernetes workloads to the internet, increasing the risk of unauthorized access, lateral movement, and potential exploitation. Attackers can target misconfigured workloads, open services, or unsecured API endpoints. By creating EKS clusters with private nodes, organizations can restrict access, limit exposure to public threats, and enforce network segmentation, ensuring that workloads remain secure and isolated within a private VPC environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.11", + "Description": "Ensure Elasticache Cluster is not using a public subnet", + "Checks": [ + "elasticache_cluster_uses_public_subnet" + ], + "Attributes": [ + { + "Title": "Elasticache Cluster is not using a public subnet", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon ElastiCache provides in-memory caching services using Redis and Memcached. By default, ElastiCache clusters can be deployed in either public or private subnets. If an ElastiCache cluster is placed in a public subnet, it becomes accessible from the internet, which significantly increases the risk of unauthorized access and data breaches. To enhance security, ElastiCache clusters should only be deployed in private subnets, ensuring restricted access within a VPC.", + "AdditionalInformation": "Deploying an ElastiCache cluster in a public subnet exposes it to external threats, such as unauthorized access, brute-force attacks, and potential data exfiltration. Attackers could exploit misconfigurations to access cached data or disrupt services. By restricting ElastiCache clusters to private subnets, organizations can limit access to trusted resources, enforce VPC security controls, and reduce the attack surface, ensuring secure and efficient caching operations.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.10", + "Description": "Ensure no Elastic Load Balancers are facing internet", + "Checks": [ + "elbv2_internet_facing" + ], + "Attributes": [ + { + "Title": "No Elastic Load Balancers are facing internet", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic Load Balancers (ELBs) distribute incoming traffic across multiple targets, such as EC2 instances, containers, and Lambda functions. By default, ELBs can be configured as either internet-facing or internal (private). If an ELB is publicly accessible, it exposes backend services to the internet, increasing the risk of unauthorized access and attacks. To enhance security, ELBs should be restricted to private networks unless explicitly required and properly secured.", + "AdditionalInformation": "Publicly accessible Elastic Load Balancers can serve as entry points for unauthorized traffic, brute-force attacks, and potential data breaches. Attackers may exploit misconfigured security groups, open ports, or exposed application endpoints behind the load balancer. To reduce security risks, ELBs should be configured as internal (private), allowing access only from trusted networks, VPNs, or specific VPCs, ensuring that backend services remain protected and isolated from external threats.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.11", + "Description": "Ensure EMR Account Public Access Block enabled", + "Checks": [ + "emr_cluster_account_public_block_enabled" + ], + "Attributes": [ + { + "Title": "EMR Account Public Access Block enabled", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic MapReduce (EMR) is a managed big data processing service that can access S3, EC2, and other AWS resources. The EMR Account Public Access Block setting helps prevent public access to EMR resources, such as data stored in S3 buckets. If this setting is not enabled, there is a risk that EMR-related data and configurations could be exposed to the public, leading to unauthorized access or data breaches. To enhance security, the Public Access Block should be enabled for the EMR account.", + "AdditionalInformation": "Allowing public access to EMR resources increases the risk of data leaks, unauthorized access, and compliance violations. Attackers could exploit misconfigured policies or publicly accessible S3 buckets to access sensitive data processed by EMR. Enabling EMR Account Public Access Block ensures that S3 data and other EMR-related resources cannot be accessed publicly, reducing exposure and maintaining strong access controls in AWS.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.12", + "Description": "Ensure EMR cluster is not publicly accessible", + "Checks": [ + "emr_cluster_publicly_accesible" + ], + "Attributes": [ + { + "Title": "EMR cluster is not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Elastic MapReduce (EMR) is a managed service for processing big data workloads using Apache Spark, Hadoop, and other frameworks. By default, EMR clusters can be configured with public or private access. If an EMR cluster is publicly accessible, it exposes data processing nodes and services to the internet, increasing the risk of unauthorized access and potential exploitation. To enhance security, EMR clusters should only be deployed in private subnets and restricted to trusted networks.", + "AdditionalInformation": "Publicly accessible EMR clusters increase the risk of data breaches, unauthorized access, and attacks on running workloads. Malicious actors could exploit misconfigured security groups, open ports, or weak authentication settings to compromise the cluster. To reduce exposure, EMR clusters should be placed in private subnets, restricted using VPC security controls, IAM permissions, and firewall rules, ensuring secure data processing and access management.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.13", + "Description": "Ensure that your AWS EventBridge event bus is not exposed to everyone", + "Checks": [ + "eventbridge_bus_exposed" + ], + "Attributes": [ + { + "Title": "AWS EventBridge event bus is not exposed to everyone", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS EventBridge is a serverless event bus service that enables communication between AWS services, third-party applications, and custom event sources. By default, EventBridge event buses can be configured to allow events from any AWS account or external source. If an event bus is exposed to everyone, unauthorized entities could send events to your environment, potentially leading to security risks, data injection attacks, or service disruptions. To enhance security, event buses should be restricted to specific AWS accounts, services, or trusted IAM roles.", + "AdditionalInformation": "Allowing unrestricted access to an EventBridge event bus increases the risk of malicious event injection, unauthorized access, and data manipulation. Attackers could flood the event bus with malicious events, leading to unexpected behavior, security breaches, or excessive AWS costs. To reduce exposure, event buses should be secured using IAM policies and resource-based permissions, ensuring that only trusted AWS services and accounts can send or receive events.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.12", + "Description": "Ensure S3 Glacier vaults have not policies which allow access to everyone", + "Checks": [ + "glacier_vaults_policy_public_access" + ], + "Attributes": [ + { + "Title": "S3 Glacier vaults have not policies which allow access to everyone", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon S3 Glacier provides low-cost, long-term storage for archival data. Glacier vaults can be configured with resource-based policies that control access. If a Glacier vault policy allows access to everyone, unauthorized users could retrieve or delete archived data, leading to data exposure or loss. To enhance security, Glacier vault policies should be restricted to specific AWS accounts, IAM roles, or trusted entities, ensuring only authorized users can access or manage archived data.", + "AdditionalInformation": "Allowing public access to S3 Glacier vaults poses a significant security risk, increasing the chance of data breaches, unauthorized deletions, or compliance violations. Attackers could restore and download sensitive archived data if the vault is misconfigured. To prevent unauthorized access, Glacier vaults should have strict access controls, using IAM policies, encryption, and resource-based permissions, ensuring that only trusted users and systems can interact with archived data.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.13", + "Description": "Ensure Glue Data Catalogs are not publicly accessible", + "Checks": [ + "glue_data_catalogs_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "Glue Data Catalogs are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "AWS Glue Data Catalog is a centralized metadata repository used to store and manage schema information for data lakes and analytics workflows. By default, Glue Data Catalogs can be configured to allow public access, which poses a significant security risk if sensitive metadata is exposed. To enhance security, Glue Data Catalogs should be restricted to specific AWS accounts, IAM roles, or trusted services, ensuring that only authorized users can access or modify catalog information.", + "AdditionalInformation": "Allowing public access to Glue Data Catalogs increases the risk of unauthorized access, data leaks, and compliance violations. Attackers could gain insights into an organization’s data structure or modify catalog entries, leading to potential data corruption or unauthorized data exposure. To reduce security risks, Glue Data Catalogs should be secured using IAM policies, resource-based permissions, and AWS Lake Formation, ensuring that only trusted accounts and services can interact with metadata.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.14", + "Description": "Ensure Kafka Cluster is not exposed to the public", + "Checks": [ + "kafka_cluster_is_public" + ], + "Attributes": [ + { + "Title": "Kafka Cluster is not exposed to the public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Managed Streaming for Apache Kafka (MSK) allows organizations to build and manage real-time data streaming applications. If a Kafka cluster is publicly accessible, it exposes data streams, configurations, and messaging topics to the internet, increasing the risk of unauthorized access, data interception, and service disruptions. To enhance security, Kafka clusters should be restricted to private networks, ensuring that only trusted AWS resources, VPCs, and IAM-authenticated users can interact with the service.", + "AdditionalInformation": "Exposing a Kafka cluster to the public internet creates significant security risks, including unauthorized data ingestion, data leaks, and message tampering. Attackers could consume, modify, or inject malicious data into Kafka topics, disrupting real-time analytics and application workflows. To mitigate these risks, Kafka clusters should be deployed in private subnets, with access restricted via VPC security groups, IAM policies, and AWS PrivateLink, ensuring secure and controlled data streaming.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.14", + "Description": "Ensure there are no internet exposed KMS keys", + "Checks": [ + "kms_key_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "No internet exposed KMS keys", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "AWS Key Management Service (KMS) provides secure encryption key management for data encryption and cryptographic operations. If KMS keys are exposed to the internet, unauthorized entities could potentially use, modify, or compromise encryption keys, leading to data breaches and security vulnerabilities. To enhance security, KMS keys should be restricted to trusted AWS accounts, IAM roles, and specific AWS services, ensuring that only authorized users and systems can access and manage them.", + "AdditionalInformation": "Exposing KMS keys to the public poses a critical security risk, as compromised keys can lead to unauthorized data decryption, loss of data integrity, and compliance violations. Attackers could potentially use public KMS keys to encrypt or decrypt sensitive data, undermining security controls. To prevent unauthorized access, KMS key policies should enforce strict access control using IAM permissions, VPC endpoint policies, and AWS PrivateLink, ensuring that encryption operations remain fully secured and isolated from the public internet.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.15", + "Description": "Ensure lightsail database is not in public mode", + "Checks": [ + "lightsail_database_public" + ], + "Attributes": [ + { + "Title": "Lightsail database not public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Lightsail Databases provide managed database solutions for applications. If a Lightsail database is set to public mode, it is directly accessible from the internet, increasing the risk of unauthorized access and data breaches. To enhance security, Lightsail databases should be configured in private mode, ensuring they are accessible only from trusted instances, private networks, or VPN connections.", + "AdditionalInformation": "Publicly accessible Lightsail databases expose sensitive data to unauthorized access, brute-force attacks, and potential exploitation. Attackers can attempt to compromise credentials, inject malicious queries, or exfiltrate data. To mitigate these risks, Lightsail databases should remain private, with access controlled through firewalls, IAM authentication, and private networking configurations, ensuring secure database connectivity and data protection.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.16", + "Description": "Ensure that Lightsail instances are not publicly accessible", + "Checks": [ + "lightsail_instance_public" + ], + "Attributes": [ + { + "Title": "Lightsail instances are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Lightsail instances provide a simple way to deploy and manage cloud-based virtual machines. If a Lightsail instance is publicly accessible, it can be directly reached from the internet, increasing the risk of unauthorized access, attacks, and data breaches. To enhance security, Lightsail instances should be restricted to private access, ensuring they are reachable only through secure connections, such as VPNs, bastion hosts, or private networking configurations.", + "AdditionalInformation": "Publicly exposed Lightsail instances create a larger attack surface, making them vulnerable to brute-force attacks, unauthorized access, and exploitation of software vulnerabilities. Attackers could compromise credentials, gain control over the instance, or disrupt services. To mitigate these risks, Lightsail instances should be secured using firewalls, private IP configurations, security group restrictions, and IAM-based access controls, ensuring that only trusted users and networks can connect.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.17", + "Description": "Ensure MQ brokers are not publicly accessible", + "Checks": [ + "mq_broker_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "MQ brokers not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS MQ brokers manage message queues for applications, facilitating secure and reliable communication between distributed services. If an MQ broker is publicly accessible, it can be reached from the internet, increasing the risk of unauthorized access, message interception, and data breaches. To enhance security, MQ brokers should be restricted to private networks, ensuring they are accessible only from trusted VPCs, private endpoints, or secure VPN connections.", + "AdditionalInformation": "Publicly exposed MQ brokers pose a significant security risk, as attackers can attempt to intercept messages, inject malicious data, or disrupt message delivery. This could lead to data manipulation, unauthorized access to sensitive information, and system-wide outages. To mitigate these risks, MQ brokers should be configured within private subnets, with access restricted using security groups, IAM policies, and VPC endpoint controls, ensuring secure and controlled message queue operations.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.18", + "Description": "Ensure NeptuneDB manual cluster snapshot is not public", + "Checks": [ + "neptune_cluster_public_snapshot" + ], + "Attributes": [ + { + "Title": "NeptuneDB manual cluster snapshot is not public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon NeptuneDB manual cluster snapshots store backups of graph database clusters, containing sensitive data such as relationships, metadata, and application configurations. By default, NeptuneDB snapshots are private, but they can be manually shared or made public, which can expose critical database information. To enhance security, NeptuneDB manual snapshots should never be publicly accessible, ensuring they are only shared with trusted AWS accounts when necessary.", + "AdditionalInformation": "Publicly accessible NeptuneDB snapshots pose a significant security risk, as attackers could restore the snapshot in their own AWS account and gain full access to the database contents. This could lead to data leaks, compliance violations, and unauthorized access to sensitive business information. To prevent data exposure, NeptuneDB snapshots should be restricted using IAM policies and AWS resource-based permissions, ensuring that only authorized users and services can access and manage database backups securely.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.19", + "Description": "Ensure Neptune Cluster is not using a public subnet", + "Checks": [ + "neptune_cluster_uses_public_subnet" + ], + "Attributes": [ + { + "Title": "Neptune Cluster is not using a public subnet", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Neptune clusters provide a fully managed graph database service designed for applications requiring complex relationship queries. By default, Neptune clusters can be deployed in either public or private subnets. If a Neptune cluster is placed in a public subnet, it becomes accessible from the internet, significantly increasing the risk of unauthorized access and data breaches. To enhance security, Neptune clusters should only be deployed in private subnets, ensuring access is restricted to trusted VPCs, IAM roles, and security group configurations.", + "AdditionalInformation": "Deploying a Neptune cluster in a public subnet exposes the database endpoints to external threats, making them vulnerable to brute-force attacks, unauthorized queries, and data exfiltration. Attackers could exploit misconfigurations to gain access to sensitive graph data, leading to potential compliance violations and security incidents. To reduce exposure, Neptune clusters should be restricted to private subnets, with access controlled through VPC security groups, IAM authentication, and private endpoint configurations, ensuring secure database operations and protected data access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.20", + "Description": "Ensure Amazon Opensearch/Elasticsearch domains are not publicly accessible", + "Checks": [ + "opensearch_service_domains_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "Amazon Opensearch/Elasticsearch domains are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon OpenSearch (formerly Elasticsearch) domains provide search, analytics, and log management capabilities for applications. If an OpenSearch/Elasticsearch domain is publicly accessible, it can be reached from the internet, exposing sensitive data and administrative controls to unauthorized users. To enhance security, OpenSearch domains should be restricted to private networks, ensuring access is limited to trusted VPCs, IAM roles, or specific security group rules.", + "AdditionalInformation": "Publicly accessible OpenSearch/Elasticsearch domains pose a significant security risk, as attackers could execute unauthorized queries, modify data, or gain administrative control over the cluster. This could lead to data breaches, service disruptions, and compliance violations. To mitigate these risks, OpenSearch domains should be deployed in private subnets, with access controlled using VPC restrictions, fine-grained access control (FGAC), IAM policies, and security group rules, ensuring secure and isolated search and analytics operations.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.15", + "Description": "Ensure that S3 buckets have not policies which allow WRITE access", + "Checks": [ + "s3_bucket_policy_public_write_access" + ], + "Attributes": [ + { + "Title": "S3 buckets have not policies which allow WRITE access", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon S3 buckets store and manage data, files, and application assets. Bucket policies control access permissions, and if an S3 bucket has a policy that allows WRITE access to everyone, unauthorized users can upload, modify, or delete objects, leading to data tampering, security breaches, or service disruptions. To enhance security, S3 bucket policies should be restricted to specific AWS accounts, IAM roles, or trusted services, ensuring only authorized users have WRITE permissions.", + "AdditionalInformation": "Allowing unrestricted WRITE access to an S3 bucket increases the risk of unauthorized modifications, data injection attacks, and accidental data loss. Attackers could upload malicious files, delete critical data, or overwrite important configurations. To prevent unauthorized changes, S3 bucket policies should explicitly deny public WRITE access, enforce least privilege access control, and use AWS Block Public Access settings to ensure secure and controlled data storage.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.16", + "Description": "Ensure there are no S3 buckets listable by Everyone or Any AWS customer", + "Checks": [ + "s3_bucket_public_list_acl" + ], + "Attributes": [ + { + "Title": "No S3 buckets are listable by Everyone or Any AWS customer", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon S3 buckets store sensitive data and should have restricted access permissions. If an S3 bucket is listable by Everyone or Any AWS customer, unauthorized users can enumerate the objects within the bucket, potentially exposing sensitive information such as filenames, metadata, or even public datasets. To enhance security, S3 bucket permissions should be configured to restrict LIST access to only authorized IAM roles, AWS accounts, or specific services.", + "AdditionalInformation": "Allowing public or AWS-wide LIST access increases the risk of data enumeration, unauthorized access, and information leaks. Attackers or unauthorized users could identify and analyze stored files, extract metadata, or infer sensitive data. To mitigate this risk, S3 bucket policies should explicitly deny public LIST access, enforce least privilege permissions, and use AWS Block Public Access settings to prevent unintended data exposure.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.17", + "Description": "Ensure there are no S3 buckets writable by Everyone or Any AWS customer", + "Checks": [ + "s3_bucket_public_write_acl" + ], + "Attributes": [ + { + "Title": "No S3 buckets writable by Everyone or Any AWS customer", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Amazon S3 buckets should have strict access controls to prevent unauthorized modifications. If an S3 bucket is writable by Everyone or Any AWS customer, it allows unauthorized users to upload, modify, or delete objects, leading to data corruption, security breaches, and compliance risks. To enhance security, S3 bucket permissions should be restricted to trusted IAM roles, AWS accounts, or specific services.", + "AdditionalInformation": "Allowing public or AWS-wide WRITE access creates a significant security risk, as attackers can inject malicious files, overwrite critical data, or delete essential objects. This could lead to data loss, malware distribution, or unauthorized system modifications. To prevent unauthorized changes, S3 bucket policies should explicitly deny public WRITE access, enforce least privilege access, and use AWS Block Public Access settings to secure data integrity and prevent unauthorized modifications.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.21", + "Description": "Ensure Amazon SageMaker Notebook instances have not direct internet access", + "Checks": [ + "sagemaker_notebook_instance_without_direct_internet_access_configured" + ], + "Attributes": [ + { + "Title": "Amazon SageMaker Notebook instances have not direct internet access", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon SageMaker Notebook instances provide an interactive environment for machine learning development and data analysis. By default, these instances can be configured with direct internet access, which increases the risk of unauthorized access, data leaks, and exposure to malicious external threats. To enhance security, SageMaker Notebook instances should be restricted to private networks, ensuring they are accessed only through secure VPC connections, IAM authentication, or VPNs.", + "AdditionalInformation": "Allowing direct internet access to SageMaker Notebook instances poses a significant security risk, as attackers could exploit misconfigurations, exfiltrate data, or inject malicious code. Publicly accessible notebooks can lead to data breaches, intellectual property theft, or compromised model training workflows. To mitigate these risks, SageMaker Notebook instances should be configured within private subnets, with internet access disabled, and restricted using security groups, IAM policies, and VPC endpoint configurations to ensure secure and controlled machine learning operations.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.18", + "Description": "Ensure Secrets Manager secrets are not publicly accessible", + "Checks": [ + "secretsmanager_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "Secrets Manager secrets are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "AWS Secrets Manager is used to securely store and manage sensitive information, such as API keys, database credentials, and encryption keys. By default, Secrets Manager secrets should be restricted to authorized IAM roles and AWS services. If a secret is publicly accessible, it can be exposed to unauthorized users, leading to data leaks, security breaches, and potential exploitation of sensitive credentials. To enhance security, Secrets Manager secrets should be strictly controlled using IAM policies and resource-based permissions.", + "AdditionalInformation": "Allowing public access to Secrets Manager secrets creates a critical security vulnerability, as attackers could retrieve, misuse, or exfiltrate sensitive information. Compromised secrets could lead to unauthorized access to databases, applications, or cloud services, resulting in data breaches, financial loss, or compliance violations. To mitigate this risk, Secrets Manager secrets should be restricted using least privilege IAM permissions, encrypted with AWS KMS, and accessed only by trusted AWS services and roles, ensuring secure and controlled secret management.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.22", + "Description": "Ensure that SES identities are not publicly accessible", + "Checks": [ + "ses_identity_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "SES identities are not publicly accessible", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Simple Email Service (SES) identities (such as email addresses or domains) are used to send and receive emails through AWS. By default, SES identities should be restricted to authorized AWS accounts and IAM roles. If an SES identity is publicly accessible, unauthorized users could send emails using the identity, leading to email spoofing, phishing attacks, or misuse of the domain for malicious purposes. To enhance security, SES identities should be properly restricted using IAM policies and verified senders.", + "AdditionalInformation": "Allowing public access to SES identities creates a security and reputational risk, as attackers could impersonate the identity, send spam, or launch phishing campaigns. This could lead to domain blacklisting, compliance violations, and damage to the organization’s email reputation. To mitigate these risks, SES identities should be restricted to trusted AWS accounts and IAM roles, ensuring that only authorized services and users can send emails, protecting the integrity and security of email communications.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.23", + "Description": "Ensure SQS queues have not policy set as Public", + "Checks": [ + "sqs_queues_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "SQS queues have not policy set as Public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Amazon Simple Queue Service (SQS) queues enable asynchronous message processing between distributed systems. By default, SQS queues should be restricted to authorized AWS accounts and IAM roles. If an SQS queue has a public policy, it allows anyone on the internet to send, receive, or delete messages, leading to data leaks, unauthorized message injection, and potential denial-of-service (DoS) attacks. To enhance security, SQS queue policies should be configured to allow access only to trusted AWS accounts, IAM roles, or specific AWS services.", + "AdditionalInformation": "Publicly accessible SQS queues pose a significant security risk, as attackers could inject malicious messages, disrupt processing workflows, or delete critical messages, leading to system failures and data integrity issues. To prevent unauthorized access, SQS policies should explicitly deny public access, enforce least privilege access control, and use IAM policies and VPC endpoint restrictions to ensure secure and controlled messaging operations.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.3.24", + "Description": "Ensure that there are not SSM Documents set as public", + "Checks": [ + "ssm_documents_set_as_public" + ], + "Attributes": [ + { + "Title": "No SSM Documents are set as public", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "AWS Systems Manager (SSM) Documents define configuration, automation, and maintenance tasks for AWS resources. By default, SSM documents should be restricted to specific AWS accounts, IAM roles, or AWS services. If an SSM document is set as public, unauthorized users could access, modify, or execute automation tasks on AWS infrastructure, leading to misconfigurations, security breaches, or unintended system modifications. To enhance security, SSM documents should be kept private and assigned only to trusted AWS entities.", + "AdditionalInformation": "Publicly accessible SSM documents pose a significant security risk, as attackers could execute malicious commands, modify system configurations, or disrupt AWS operations. This could lead to unauthorized access, data leaks, compliance violations, or system downtime. To prevent security threats, SSM documents should explicitly deny public access, enforce least privilege permissions, and use IAM policies and resource-based access controls to ensure only trusted users and systems can manage AWS resources.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.1", + "Description": "Ensure CloudTrail is enabled in all regions", + "Checks": [ + "cloudtrail_multi_region_enabled" + ], + "Attributes": [ + { + "Title": "CloudTrail enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "AWS CloudTrail is a service that records and monitors AWS API calls across an account, providing detailed logs of who performed what action, when, and from where. CloudTrail captures API activity from the AWS Management Console, SDKs, CLI, and AWS services such as CloudFormation. The logs include key details such as the identity of the API caller, timestamp, source IP address, request parameters, and response elements.", + "AdditionalInformation": "CloudTrail enhances security, auditing, and compliance by providing a complete history of API activities in an AWS account. Enabling a multi-region trail ensures: Detection of unauthorized activity in rarely used AWS regions. Global Service Logging is automatically enabled, capturing API calls from global services such as IAM and AWS Organizations. Tracking of all management events, ensuring that both read and write operations across AWS resources are recorded for improved security monitoring and compliance.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.2", + "Description": "Ensure CloudTrail log file validation is enabled", + "Checks": [ + "cloudtrail_log_file_validation_enabled" + ], + "Attributes": [ + { + "Title": "CloudTrail file validation enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "AWS CloudTrail log file validation generates digitally signed digest files containing cryptographic hashes of each log file stored in Amazon S3. These digest files allow users to verify whether logs have been altered, deleted, or remain unchanged after being delivered by CloudTrail. Enabling log file validation ensures data integrity and auditability for security and compliance purposes.", + "AdditionalInformation": "Enabling log file validation enhances security by ensuring the integrity of CloudTrail logs, preventing tampering or unauthorized modifications. This helps: Detect log file alterations, ensuring logs remain trustworthy for audits and investigations. Improve compliance with frameworks that require log integrity, such as PCI DSS, SOC 2, and ISO 27001. Strengthen forensic capabilities, allowing security teams to verify log authenticity in case of a security incident.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.1", + "Description": "Ensure AWS Config is enabled in all regions", + "Checks": [ + "config_recorder_all_regions_enabled" + ], + "Attributes": [ + { + "Title": "AWS Config is enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "AWS Config is a service that continuously monitors, records, and evaluates configuration changes in AWS resources within an account. It tracks configuration items, relationships between resources, and changes over time, delivering logs for security analysis, change management, and compliance auditing. To ensure comprehensive monitoring, AWS Config should be enabled in all regions.", + "AdditionalInformation": "Enabling AWS Config in all regions improves security, visibility, and compliance by: Tracking resource changes, allowing for quick identification of misconfigurations. Supporting security audits and forensic investigations by maintaining a historical record of configurations.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.3", + "Description": "Ensure that server access logging is enabled on the CloudTrail S3 bucket", + "Checks": [ + "cloudtrail_logs_s3_bucket_access_logging_enabled" + ], + "Attributes": [ + { + "Title": "Server access logging is enabled on the CloudTrail S3 bucket", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Server access logging provides detailed records of requests made to an S3 bucket, including request type, accessed resources, timestamp, and requester details. Enabling server access logging on the CloudTrail S3 bucket ensures that all interactions with CloudTrail logs are recorded, improving security visibility and auditability", + "AdditionalInformation": "Enabling server access logging on CloudTrail S3 buckets enhances security monitoring, incident response, and compliance by: Capturing all events affecting CloudTrail logs, helping detect unauthorized access or modifications. Providing an audit trail for forensic investigations and compliance reporting. Enhancing security workflows by storing access logs in a separate, dedicated logging bucket for improved log integrity and analysis.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.2.3", + "Description": "Ensure CloudTrail logs are encrypted at rest using KMS CMKs", + "Checks": [ + "cloudtrail_kms_encryption_enabled" + ], + "Attributes": [ + { + "Title": "CloudTrail logs are encrypted at rest using KMS CMKs", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "AWS CloudTrail records API activity across an AWS account, and its logs contain sensitive security and operational data. AWS Key Management Service (KMS) provides encryption key management using customer-managed keys (CMKs) and Hardware Security Modules (HSMs) to ensure secure key storage and usage. CloudTrail logs can be encrypted using Server-Side Encryption (SSE) with KMS (SSE-KMS) to add an extra layer of protection and access control", + "AdditionalInformation": "Using SSE-KMS encryption for CloudTrail logs enhances security by adding an extra layer of access control. This ensures that only authorized users with both S3 read permissions and KMS decryption rights can access log data, protecting sensitive security information from unauthorized access or tampering. It also helps maintain compliance with security and regulatory standards by enforcing strict encryption controls.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure rotation for customer-created symmetric CMKs is enabled", + "Checks": [ + "kms_cmk_rotation_enabled" + ], + "Attributes": [ + { + "Title": "Rotation for customer-created symmetric CMKs enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "AWS Key Management Service (KMS) allows users to manage encryption keys securely. Key rotation enables the automatic replacement of the backing key (the cryptographic material tied to a customer-managed key (CMK)), ensuring continuous security without disrupting access to previously encrypted data. AWS automatically retains previous backing keys to allow seamless decryption of older data while using a newly generated key for encryption. It is recommended to enable key rotation for symmetric CMKs, as asymmetric keys do not support this feature.", + "AdditionalInformation": "Regularly rotating encryption keys minimizes the risk associated with key compromise by ensuring that newly encrypted data is protected with a fresh key, reducing the potential impact of an exposed key. Since AWS KMS retains prior backing keys for seamless decryption, rotation does not disrupt access to previously encrypted data. Implementing key rotation enhances security by limiting the exposure window of any single encryption key and aligning with best practices for cryptographic hygiene.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.4", + "Description": "Ensure VPC flow logging is enabled in all VPCs", + "Checks": [ + "vpc_flow_logs_enabled" + ], + "Attributes": [ + { + "Title": "VPC flow logging enabled in all VPCs", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "VPC Flow Logs capture and record IP traffic information for network interfaces within a VPC, allowing administrators to monitor and analyze network activity. These logs are stored in Amazon CloudWatch Logs for retrieval and analysis. It is recommended to enable VPC Flow Logs for rejected packets to track unauthorized access attempts, misconfigurations, or potential security threats within the VPC.", + "AdditionalInformation": "Enabling VPC Flow Logs for rejected traffic enhances network visibility and security monitoring by detecting suspicious activity, failed connection attempts, and potential threats. These logs help identify anomalous traffic patterns, troubleshoot connectivity issues, and support incident response workflows, improving overall security posture.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.5", + "Description": "Ensure that object-level logging for write events is enabled for S3 buckets", + "Checks": [ + "cloudtrail_s3_dataevents_write_enabled" + ], + "Attributes": [ + { + "Title": "Object-level logging for write events is enabled for S3 buckets", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "S3 object-level API operations, such as GetObject, PutObject, and DeleteObject, are classified as data events in AWS CloudTrail. By default, CloudTrail does not log data events, meaning detailed tracking of individual object interactions is not enabled. To enhance visibility and security, it is recommended to enable object-level logging for S3 buckets to monitor access and modification activities.", + "AdditionalInformation": "Enabling object-level logging helps organizations meet compliance requirements, enhance security monitoring, and detect unauthorized access. It allows administrators to analyze user behavior, track modifications to critical data, and respond to security incidents in real time using Amazon CloudWatch Events, ensuring greater control over S3 bucket activity.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.6", + "Description": "Ensure that object-level logging for read events is enabled for S3 buckets", + "Checks": [ + "cloudtrail_s3_dataevents_read_enabled" + ], + "Attributes": [ + { + "Title": "Object-level logging for read events is enabled for S3 buckets", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "S3 object-level API operations, such as GetObject, PutObject, and DeleteObject, are classified as data events in AWS CloudTrail. By default, CloudTrail does not log data events, meaning individual object interactions are not tracked unless explicitly enabled. To improve security monitoring and compliance, it is recommended to enable object-level logging for S3 buckets.", + "AdditionalInformation": "Object-level logging enhances data security, compliance, and operational visibility by providing detailed tracking of who accessed, modified, or deleted objects within S3 buckets. This enables organizations to monitor user behavior, detect unauthorized access, and quickly respond to potential security incidents using Amazon CloudWatch Events.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.2", + "Description": "Ensure unauthorized API calls are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_unauthorized_api_calls" + ], + "Attributes": [ + { + "Title": "Unauthorized API calls are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of API calls can be achieved by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can automatically detect and respond to unauthorized API calls, improving security visibility. It is recommended to establish a metric filter and alarm for unauthorized API calls to enhance threat detection and incident response.", + "AdditionalInformation": "Monitoring unauthorized API calls helps identify potential security incidents faster, reducing the time attackers have to exploit vulnerabilities. CloudWatch provides real-time monitoring and alerting, while SIEM solutions offer centralized security event analysis. Detecting unauthorized API calls early allows organizations to take immediate action, investigate potential threats, and strengthen overall AWS security posture.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.3", + "Description": "Ensure management console sign-in without MFA is monitored", + "Checks": [ + "cloudwatch_log_metric_filter_sign_in_without_mfa" + ], + "Attributes": [ + { + "Title": "Management console sign-in without MFA is monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By setting up metric filters and alarms, organizations can detect and respond to security risks effectively. It is recommended to establish a metric filter and alarm for AWS console logins that are not protected by multi-factor authentication (MFA) to enhance security monitoring.", + "AdditionalInformation": "Monitoring console logins without MFA improves visibility into accounts that lack strong authentication controls. Accounts without MFA are more vulnerable to credential theft, brute-force attacks, and unauthorized access. By detecting these login attempts in real-time, organizations can identify security gaps, enforce MFA policies, and reduce the risk of account compromise.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.4", + "Description": "Ensure usage of the root account is monitored", + "Checks": [ + "cloudwatch_log_metric_filter_root_usage" + ], + "Attributes": [ + { + "Title": "Usage of root account monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be achieved by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. Setting up metric filters and alarms helps detect potential security threats. It is recommended to establish a metric filter and alarm for root account login attempts to identify unauthorized access or improper use of the highly privileged root account.", + "AdditionalInformation": "Monitoring root account logins enhances visibility into the usage of the most privileged AWS account, which should be used only in exceptional cases. Frequent or unauthorized root logins increase security risks by exposing critical administrative controls. Detecting root login attempts in real time enables organizations to identify potential security incidents, enforce least privilege principles, and limit unnecessary use of the root account.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.5", + "Description": "Ensure IAM policy changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_policy_changes" + ], + "Attributes": [ + { + "Title": "IAM policy changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can detect critical security events. It is recommended to establish a metric filter and alarm for changes to Identity and Access Management (IAM) policies to track modifications that could affect authentication and authorization controls.", + "AdditionalInformation": "Monitoring IAM policy changes helps ensure that access controls remain secure and intact. Unauthorized or unintended modifications to IAM policies can lead to privilege escalation, misconfigurations, and security breaches. Detecting these changes in real-time allows organizations to respond quickly to potential threats, enforce least privilege principles, and maintain a strong security posture.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.6", + "Description": "Ensure CloudTrail configuration changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" + ], + "Attributes": [ + { + "Title": "CloudTrail configuration changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can track critical security events. It is recommended to establish a metric filter and alarm to detect changes to CloudTrail configurations, ensuring that logging remains active and tamper-proof.", + "AdditionalInformation": "Monitoring CloudTrail configuration changes helps maintain continuous visibility into AWS account activity. Unauthorized modifications to CloudTrail settings could disable or alter logging, potentially allowing malicious activity to go undetected. Detecting these changes in real time enables organizations to quickly respond to threats, enforce security best practices, and ensure compliance with auditing requirements.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.7", + "Description": "Ensure AWS Management Console authentication failures are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_authentication_failures" + ], + "Attributes": [ + { + "Title": "AWS Management Console authentication failures are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By setting up metric filters and alarms, organizations can detect potential security threats. It is recommended to establish a metric filter and alarm for failed console authentication attempts to identify potential unauthorized access attempts or brute-force attacks.", + "AdditionalInformation": "Monitoring failed console logins helps detect brute-force attempts and unauthorized access attempts early. Repeated failed authentication attempts can indicate malicious activity, and tracking them allows security teams to identify suspicious IP addresses, correlate with other security events, and take proactive measures to protect AWS accounts.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.8", + "Description": "Ensure disabling or scheduled deletion of customer created CMKs is monitored", + "Checks": [ + "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk" + ], + "Attributes": [ + { + "Title": "Disabling or scheduled deletion of customer created CMKs is monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be achieved by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can detect security-critical changes. It is recommended to set up a metric filter and alarm for customer-managed KMS keys (CMKs) that are disabled or scheduled for deletion to prevent unintended encryption key loss.", + "AdditionalInformation": "Disabling or deleting a customer-managed CMK can render encrypted data permanently inaccessible, leading to data loss and service disruptions. Monitoring CMK state changes helps detect unauthorized or accidental modifications, ensuring encryption keys remain available and aligned with security policies. Detecting such changes in real time allows organizations to prevent data loss, maintain compliance, and take corrective action if needed.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.9", + "Description": "Ensure S3 bucket policy changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes" + ], + "Attributes": [ + { + "Title": "S3 bucket policy changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can track critical security-related changes. It is recommended to set up a metric filter and alarm for modifications to S3 bucket policies to detect potential misconfigurations or unauthorized access changes.", + "AdditionalInformation": "Monitoring S3 bucket policy changes helps detect and respond to overly permissive configurations that could expose sensitive data. Unauthorized or accidental modifications may grant public access or excessive permissions, increasing the risk of data breaches and compliance violations. Real-time alerts allow security teams to quickly identify, investigate, and correct risky policy changes, reducing exposure and strengthening data security.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.10", + "Description": "Ensure AWS Config configuration changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled" + ], + "Attributes": [ + { + "Title": "AWS Config configuration changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by directing CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. By configuring metric filters and alarms, organizations can detect critical configuration changes. It is recommended to establish a metric filter and alarm for modifications to AWS Config’s configurations to ensure continuous monitoring and compliance.", + "AdditionalInformation": "Monitoring AWS Config configuration changes helps maintain visibility and control over resource configurations. Unauthorized or accidental modifications to AWS Config settings may result in gaps in security monitoring, misconfigurations going undetected, and compliance violations. Real-time alerts allow security teams to quickly detect, investigate, and respond to changes, ensuring the integrity of configuration tracking across the AWS environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.11", + "Description": "Ensure security group changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_security_group_changes" + ], + "Attributes": [ + { + "Title": "Security group changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. Security groups act as stateful packet filters that control inbound and outbound traffic within a VPC. It is recommended to establish a metric filter and alarm to detect changes to security groups to prevent unauthorized modifications that could expose resources to security threats.", + "AdditionalInformation": "Monitoring security group changes helps ensure that network access controls remain secure and that AWS resources are not unintentionally exposed. Unauthorized or accidental modifications to security groups can create security gaps, increasing the risk of data breaches and unauthorized access. Real-time alerts enable security teams to detect, investigate, and respond to security group changes quickly, maintaining a strong network security posture.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.12", + "Description": "Ensure Network Access Control List (NACL) changes are monitored", + "Checks": [ + "cloudwatch_changes_to_network_acls_alarm_configured" + ], + "Attributes": [ + { + "Title": "Network Access Control List (NACL) changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. Network Access Control Lists (NACLs) act as stateless packet filters that control inbound and outbound traffic for subnets within a VPC. It is recommended to establish a metric filter and alarm to detect changes to NACLs to prevent unauthorized modifications that could compromise network security.", + "AdditionalInformation": "Monitoring NACL changes helps ensure that network traffic controls remain properly configured and that AWS resources are not unintentionally exposed. Unauthorized or accidental modifications to NACL rules can lead to misconfigured security policies, increased attack surfaces, and potential data breaches. Real-time alerts enable security teams to detect, investigate, and respond to NACL modifications quickly, maintaining strong network security controls.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.13", + "Description": "Ensure changes to network gateways are monitored", + "Checks": [ + "cloudwatch_changes_to_network_gateways_alarm_configured" + ], + "Attributes": [ + { + "Title": "Changes to network gateways are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. Network gateways serve as the primary route for traffic entering and leaving a VPC, facilitating communication with external networks. It is recommended to establish a metric filter and alarm for changes to network gateways to ensure that network traffic is securely routed through controlled paths.", + "AdditionalInformation": "Monitoring network gateway changes helps maintain secure ingress and egress traffic flows within a VPC. Unauthorized or accidental modifications to network gateways can disrupt connectivity, introduce security vulnerabilities, or expose AWS resources to external threats. Real-time alerts enable security teams to detect, investigate, and respond to changes quickly, ensuring that all traffic follows a controlled and secure routing policy.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.14", + "Description": "Ensure route table changes are monitored", + "Checks": [ + "cloudwatch_changes_to_network_route_tables_alarm_configured" + ], + "Attributes": [ + { + "Title": "Route table changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be achieved by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. Route tables determine how network traffic is directed between subnets and network gateways within a VPC. It is recommended to establish a metric filter and alarm for changes to route tables to detect unauthorized or accidental modifications that could impact network security and connectivity.", + "AdditionalInformation": "Monitoring route table changes ensures that VPC traffic follows the intended and secure routing paths. Unauthorized modifications can result in misrouted traffic, exposure of sensitive resources, or connectivity disruptions. Real-time alerts enable security teams to detect, investigate, and respond to route table changes promptly, preventing potential security risks and maintaining a controlled and secure network environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.15", + "Description": "Ensure VPC changes are monitored", + "Checks": [ + "cloudwatch_changes_to_vpcs_alarm_configured" + ], + "Attributes": [ + { + "Title": "VPC changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be implemented by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. AWS accounts can contain multiple Virtual Private Clouds (VPCs), and VPC peering connections allow network traffic to flow between them. It is recommended to establish a metric filter and alarm for changes made to VPC configurations to detect unauthorized modifications that could impact network security and connectivity.", + "AdditionalInformation": "Monitoring VPC configuration changes helps ensure network integrity, security, and proper traffic flow within AWS environments. Unauthorized or accidental modifications can result in misconfigured routing, unintended internet exposure, or connectivity disruptions between resources. Real-time alerts enable security teams to detect, investigate, and respond to VPC changes promptly, preventing security risks and ensuring consistent network accessibility and isolation.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.16", + "Description": "Ensure AWS Organizations changes are monitored", + "Checks": [ + "cloudwatch_log_metric_filter_aws_organizations_changes" + ], + "Attributes": [ + { + "Title": "AWS Organizations changes are monitored", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Real-time monitoring of AWS API calls can be achieved by forwarding CloudTrail logs to Amazon CloudWatch Logs or an external Security Information and Event Management (SIEM) system. AWS Organizations allows centralized management of multiple AWS accounts, and modifications to its configuration can significantly impact access control, account governance, and security policies. It is recommended to establish a metric filter and alarm for changes made to AWS Organizations in the master AWS account to detect unauthorized or unintended modifications.", + "AdditionalInformation": "Monitoring AWS Organizations configuration changes helps prevent unwanted, accidental, or malicious modifications that could lead to unauthorized access, policy misconfigurations, or security breaches. Detecting changes in real time ensures that unexpected modifications can be investigated and remediated quickly, reducing the risk of compromised governance structures and ensuring compliance with organizational security policies.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.17", + "Description": "Ensure AWS Security Hub is enabled", + "Checks": [ + "securityhub_enabled" + ], + "Attributes": [ + { + "Title": "Security Hub enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "AWS Security Hub centralizes security data from multiple AWS services and third-party security tools, allowing for real-time threat detection, risk assessment, and compliance monitoring. When enabled, Security Hub aggregates, organizes, and prioritizes security findings from services such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie, as well as integrated third-party security products. This provides organizations with a unified security management platform to enhance threat visibility.", + "AdditionalInformation": "Enabling AWS Security Hub provides a comprehensive view of your security posture, helping to identify vulnerabilities, detect threats, and enforce security best practices. It allows organizations to monitor security trends, benchmark environments against industry standards, and quickly respond to high-priority security issues, strengthening overall AWS security governance and compliance.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.2.2", + "Description": "Ensure CloudWatch Log Groups have a retention policy of specific days", + "Checks": [ + "cloudwatch_log_group_retention_policy_specific_days_enabled" + ], + "Attributes": [ + { + "Title": "CloudWatch Log Groups have a retention policy of specific days", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "AWS CloudWatch Log Groups store logs from various AWS services and applications, enabling monitoring, debugging, and security auditing. By default, CloudWatch logs are retained indefinitely, which can lead to unnecessary data storage costs and compliance risks. To manage log lifecycle effectively, it is recommended to set a retention policy for CloudWatch Log Groups, ensuring logs are retained only for a specific number of days based on operational and compliance requirements.", + "AdditionalInformation": "Setting a retention policy for CloudWatch logs helps balance cost management, compliance, and security. Retaining logs for too long increases storage costs and potential exposure to sensitive data, while keeping them for too short a duration can limit forensic investigations and compliance reporting. By defining a specific retention period, organizations can ensure logs are available for troubleshooting and audits while adhering to data retention best practices and regulatory requirements.", + "LevelOfRisk": 1 + } + ] + } + ] +} diff --git a/prowler/compliance/azure/prowler_threatscore_azure.json b/prowler/compliance/azure/prowler_threatscore_azure.json new file mode 100644 index 0000000000..db479fb616 --- /dev/null +++ b/prowler/compliance/azure/prowler_threatscore_azure.json @@ -0,0 +1,1317 @@ +{ + "Framework": "ProwlerThreatScore", + "Version": "1.0", + "Provider": "Azure", + "Description": "Prowler ThreatScore Compliance Framework for Azure ensures that the Azure subscription is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + "Requirements": [ + { + "Id": "1.1.1", + "Description": "Ensure Security Defaults is enabled on Microsoft Entra ID", + "Checks": [ + "entra_security_defaults_enabled" + ], + "Attributes": [ + { + "Title": "Security Defaults enabled on Entra ID", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Microsoft Entra ID Security Defaults offer preconfigured security settings designed to protect organizations from common identity attacks at no additional cost. These settings enforce basic security measures such as MFA registration, risk-based authentication prompts, and blocking legacy authentication clients that do not support MFA. Security defaults are available to all organizations and can be enabled via the Azure portal to strengthen authentication security.", + "AdditionalInformation": "Security defaults provide built-in protections to reduce the risk of unauthorized access until organizations configure their own identity security policies. By requiring MFA, blocking weak authentication methods, and adapting authentication challenges based on risk factors, these settings create a stronger security foundation without additional licensing requirements.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.1.2", + "Description": "Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users", + "Checks": [ + "entra_privileged_user_has_mfa" + ], + "Attributes": [ + { + "Title": "MFA enabled for privileged users", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "[IMPORTANT] If your organization has Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, F5, or EM&S E3/E5) and can use Conditional Access, you may skip this section and proceed to Conditional Access. Enable multi-factor authentication (MFA) for all users, roles, and groups with write access to Azure resources. This includes both custom-created roles and built-in roles such as: Service Co-Administrators, Subscription Owners, Contributors", + "AdditionalInformation": "MFA enhances security by requiring two or more authentication factors, ensuring that only authorized users gain access. It significantly reduces the risk of unauthorized access, credential theft, and privilege escalation. By implementing MFA, attackers must compromise multiple authentication mechanisms, making breaches far more difficult and improving overall Azure resource security.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.1.3", + "Description": "Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users", + "Checks": [ + "entra_non_privileged_user_has_mfa" + ], + "Attributes": [ + { + "Title": "MFA enabled for non-privileged users", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "[IMPORTANT] If your organization has Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, F5, or EM&S E3/E5) and can use Conditional Access, you may skip this section and proceed to Conditional Access. Enable multi-factor authentication (MFA) for all non-privileged users to enhance security and prevent unauthorized access.", + "AdditionalInformation": "MFA strengthens authentication by requiring at least two verification factors, making it significantly harder for attackers to gain access using stolen credentials. Even if one authentication factor is compromised, an additional layer of security reduces the risk of unauthorized account access, enhancing overall identity and access management security.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.1.4", + "Description": "Ensure Multi-factor Authentication is Required for Windows Azure Service Management API", + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api" + ], + "Attributes": [ + { + "Title": "MFA Required for Windows Azure Service Management API", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "This recommendation ensures that users accessing the Windows Azure Service Management API (e.g., Azure PowerShell, Azure CLI, Azure Resource Manager API) are required to authenticate using multi-factor authentication (MFA) before accessing resources.", + "AdditionalInformation": "Administrative access to the Azure Service Management API should be secured with enhanced authentication measures to prevent unauthorized changes. Enforcing MFA helps mitigate the risk of credential compromise, privilege abuse, and unauthorized modifications to administrative settings. IMPORTANT: While exceptions for specific users or groups may be configured, they should be carefully tracked and periodically reviewed through an Access Review process. The policy should apply to all users by default, ensuring that only explicitly exempted accounts bypass MFA.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.1.5", + "Description": "Ensure Multi-factor Authentication is Required to access Microsoft Admin Portals", + "Checks": [ + "defender_ensure_defender_for_server_is_on" + ], + "Attributes": [ + { + "Title": "MFA Required to access Microsoft Admin Portals", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "This recommendation ensures that users accessing Microsoft Admin Portals (such as Microsoft 365 Admin, Microsoft 365 Defender, Exchange Admin Center, and Azure Portal) must authenticate using multi-factor authentication (MFA) before logging in.", + "AdditionalInformation": "Microsoft Admin Portals provide privileged access to critical settings and resources, requiring enhanced security measures. Enforcing MFA reduces the risk of unauthorized access, credential compromise, and administrative abuse, preventing intruders from making unauthorized changes to administrative settings.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.1.6", + "Description": "Ensure only MFA enabled identities can access privileged Virtual Machine", + "Checks": [ + "entra_user_with_vm_access_has_mfa" + ], + "Attributes": [ + { + "Title": "Only MFA enabled identities can access privileged Virtual Machine", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Ensure that privileged virtual machines do not allow logins from identities without multi-factor authentication (MFA) and that access is restricted to necessary permissions only. Unauthorized access can enable attackers to move laterally and misuse the virtual machine’s managed identity for further privilege escalation or unauthorized operations.", + "AdditionalInformation": "Requiring MFA for privileged VM access reduces the risk of credential compromise, lateral movement, and unauthorized access to cloud resources. Attackers can exploit valid accounts to access virtual machines and escalate privileges using the managed identity. Enforcing MFA and least privilege access helps mitigate these risks by preventing unauthorized logins and restricting administrative permissions to only what is necessary.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.2.1", + "Description": "Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes'", + "Checks": [ + "entra_policy_ensure_default_user_cannot_create_tenants" + ], + "Attributes": [ + { + "Title": "Restrict non-admin users from creating tenants is set to Yes", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Restrict the ability to create new Microsoft Entra ID or Azure AD B2C tenants to administrators or appropriately delegated users.", + "AdditionalInformation": "Limiting tenant creation to authorized administrators prevents unauthorized users from creating new tenants, reducing the risk of uncontrolled environments, misconfigurations, and potential security gaps. This ensures that only approved users can establish and manage tenant resources.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.2", + "Description": "Ensure fewer than 5 users have global administrator assignment", + "Checks": [ + "entra_global_admin_in_less_than_five_users" + ], + "Attributes": [ + { + "Title": "Fewer than 5 users have global administrator assignment", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "To maintain security and operational efficiency, it is recommended to have a minimum of two and a maximum of four users assigned the Global Administrator role in Microsoft Entra ID. This ensures redundancy while minimizing the risk of excessive privileged access.", + "AdditionalInformation": "The Global Administrator role holds broad privileges across Microsoft Entra ID services and should not be used for daily tasks. Administrators should have separate accounts for regular activities and privileged actions. Limiting the number of Global Administrators reduces the risk of unauthorized access, human error, and privilege misuse, while ensuring at least two administrators are available to prevent disruptions in case of unavailability. This approach aligns with the principle of least privilege and strengthens the security posture of an Azure tenant.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.3", + "Description": "Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'", + "Checks": [ + "entra_policy_guest_users_access_restrictions" + ], + "Attributes": [ + { + "Title": "Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Restrict guest user permissions to prevent unauthorized access to directory resources and administrative roles.", + "AdditionalInformation": "Limiting guest access ensures that guest accounts cannot enumerate users, groups, or directory objects and prevents them from being assigned administrative roles. Guest access has three levels of restriction, with the most secure option being: “Guest user access is restricted to their own directory object” (most restrictive). This setting minimizes the risk of unauthorized access and ensures guests only interact with their assigned resources.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.4", + "Description": "Ensure `User consent for applications` is set to `Do not allow user consent` ", + "Checks": [ + "entra_policy_restricts_user_consent_for_apps" + ], + "Attributes": [ + { + "Title": "`User consent for applications` is set to `Do not allow user consent` ", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Require administrators to provide consent before applications can access Microsoft Entra ID resources, preventing unauthorized or malicious app integrations.", + "AdditionalInformation": "Allowing users to grant application permissions without restrictions increases the risk of data exfiltration and privilege abuse by malicious applications. Restricting app consent to administrators ensures that only verified and approved applications gain access, protecting sensitive data and privileged accounts from unauthorized use.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.5", + "Description": "Ensure ‘User consent for applications’ Is Set To ‘Allow for Verified Publishers’", + "Checks": [ + "entra_policy_user_consent_for_verified_apps" + ], + "Attributes": [ + { + "Title": "‘User consent for applications’ Is Set To ‘Allow for Verified Publishers’", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Allow users to grant consent only for selected permissions when the request comes from a verified publisher, ensuring tighter control over third-party application access.", + "AdditionalInformation": "Restricting app consent to verified publishers helps mitigate the risk of unauthorized data access and privilege abuse. Malicious applications may attempt to exploit user-granted permissions, so ensuring only trusted, verified applications can request access enhances security while maintaining flexibility for approved integrations.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.2.6", + "Description": "Ensure Trusted Locations Are Defined", + "Checks": [ + "entra_trusted_named_locations_exists" + ], + "Attributes": [ + { + "Title": "Trusted Locations Are Defined", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Microsoft Entra ID Conditional Access allows organizations to define Named Locations and categorize them as trusted or untrusted. These locations can be based on geographical regions, specific IP addresses, or IP ranges to enhance access control policies.", + "AdditionalInformation": "Defining trusted IP addresses or ranges enables organizations to enforce Conditional Access policies based on user location. Users authenticating from trusted locations may receive fewer access restrictions, while those from untrusted sources can be subject to stricter security controls, reducing the risk of unauthorized access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.1", + "Description": "Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'", + "Checks": [ + "entra_policy_default_users_cannot_create_security_groups" + ], + "Attributes": [ + { + "Title": "Users can create security groups in Azure portals, API or PowerShell' is set to 'No'", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Limit the ability to create security groups to administrators only, preventing unauthorized users from managing group memberships.", + "AdditionalInformation": "Allowing all users to create and manage security groups can lead to uncontrolled access, misconfigurations, and potential security risks. Unless business requirements justify broader delegation, restricting security group creation to administrators ensures that group permissions and memberships are properly managed, reducing the risk of unauthorized access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.2", + "Description": "Ensure That ‘Users Can Register Applications’ Is Set to ‘No’", + "Checks": [ + "entra_policy_ensure_default_user_cannot_create_apps" + ], + "Attributes": [ + { + "Title": "‘Users Can Register Applications’ Is Set to ‘No’", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Restrict the ability to register third-party applications to administrators or appropriately delegated users, ensuring better security control over app integrations.", + "AdditionalInformation": "Allowing unrestricted application registration can expose Microsoft Entra ID data to security risks. Requiring administrator approval ensures that custom-developed applications undergo a formal security review before being granted access. Organizations may delegate permissions to developers or high-request users as needed, but policies should be reviewed to align with security best practices and operational needs.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.3", + "Description": "Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'", + "Checks": [ + "entra_policy_guest_invite_only_for_admin_roles" + ], + "Attributes": [ + { + "Title": "Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Limit the ability to send invitations to users with specific administrative roles, preventing unauthorized guest access to cloud resources.", + "AdditionalInformation": "Restricting guest invitations to designated administrators helps enforce “Need to Know” permissions, reducing the risk of unintended data exposure. By default, anyone in the organization—including guests and non-admins—can invite external users, which can lead to unauthorized access. Restricting this capability ensures that only approved accounts can extend access to the tenant, strengthening security and access control.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "1.3.4", + "Description": "Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'", + "Checks": [ + "entra_users_cannot_create_microsoft_365_groups" + ], + "Attributes": [ + { + "Title": "Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Limit Microsoft 365 group creation to administrators only, ensuring that group management remains under centralized control.", + "AdditionalInformation": "Restricting group creation to administrators prevents unauthorized or unnecessary group creation, ensuring that only appropriate groups are created and managed. This reduces the risk of misconfigurations, access issues, and uncontrolled resource sharing within the organization.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.1", + "Description": "Ensure that RDP access from the Internet is evaluated and restricted", + "Checks": [ + "network_rdp_internet_access_restricted" + ], + "Attributes": [ + { + "Title": "RDP access from the Internet is evaluated and restricted", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Regularly review Network Security Groups (NSGs) for misconfigured or overly permissive rules, especially those exposing ports and protocols to the public internet. Any unnecessary exposure should be restricted to reduce security risks.", + "AdditionalInformation": "Exposing Remote Desktop Protocol (RDP) or other critical services to the internet increases the risk of brute-force attacks, which could lead to unauthorized access to Azure Virtual Machines. Compromised VMs can be used to launch attacks on other networked resources, both inside and outside Azure. Periodic NSG evaluations help minimize attack surfaces and ensure that only explicitly required access is permitted.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.1.2", + "Description": "Ensure that SSH access from the Internet is evaluated and restricted", + "Checks": [ + "network_ssh_internet_access_restricted" + ], + "Attributes": [ + { + "Title": "SSH access from the Internet is evaluated and restricted", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Regularly review Network Security Groups (NSGs) for misconfigured or overly permissive rules, particularly those exposing SSH (port 22) or other critical services to the internet. Any unnecessary exposure should be restricted to reduce security risks.", + "AdditionalInformation": "Exposing SSH over the internet increases the risk of brute-force attacks, allowing attackers to gain unauthorized access to Azure Virtual Machines. Once compromised, a VM can be used as a pivot point to attack other machines within the Azure Virtual Network or even external systems. Periodic NSG evaluations help minimize attack surfaces and ensure that only explicitly required access is permitted.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.1.3", + "Description": "Ensure that UDP access from the Internet is evaluated and restricted", + "Checks": [ + "network_udp_internet_access_restricted" + ], + "Attributes": [ + { + "Title": "UDP access from the Internet is evaluated and restricted", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Regularly review Network Security Groups (NSGs) for misconfigured or overly permissive UDP rules, especially those exposing UDP-based services to the internet. Any unnecessary exposure should be restricted to prevent security risks.", + "AdditionalInformation": "Exposing UDP services to the internet increases the risk of Distributed Denial-of-Service (DDoS) amplification attacks, where attackers can reflect and amplify spoofed traffic from Azure Virtual Machines. Commonly exploited UDP services include DNS, NTP, SSDP, SNMP, and CLDAP, which can be used to disrupt services or launch attacks against other networked systems inside and outside Azure. Regular NSG evaluations help minimize attack surfaces and prevent VMs from being leveraged in DDoS attacks.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.4", + "Description": "Ensure that HTTP(S) access from the Internet is evaluated and restricted", + "Checks": [ + "network_http_internet_access_restricted" + ], + "Attributes": [ + { + "Title": "HTTP(S) access from the Internet is evaluated and restricted", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Regularly review Network Security Groups (NSGs) for misconfigured or overly permissive HTTP(S) rules, ensuring that exposure to the internet is necessary and narrowly configured. Restrict access where it is not explicitly required.", + "AdditionalInformation": "Exposing HTTP(S) services to the internet increases the risk of brute-force attacks, credential stuffing, and exploitation of vulnerabilities in web applications or services. If compromised, an attacker can use the affected resource as a pivot point to escalate privileges, move laterally, and compromise other Azure resources within the tenant. Periodic NSG evaluations help reduce attack surfaces and enforce least privilege access.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.5", + "Description": "Ensure an Azure Bastion Host Exists", + "Checks": [ + "network_bastion_host_exists" + ], + "Attributes": [ + { + "Title": "Ensure Azure Bastion Host Exists", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Enable Azure Bastion to securely access Azure Virtual Machines (VMs) over the internet without exposing RDP (3389/TCP) or SSH (22/TCP) ports directly to the public network. Azure Bastion provides remote access through TLS (443/TCP) while integrating with Azure Active Directory (AAD) security policies.", + "AdditionalInformation": "Using Azure Bastion eliminates the need to assign public IP addresses to VMs, reducing exposure to brute-force attacks and unauthorized access. It enhances security by enabling browser-based RDP/SSH access, leveraging Azure Active Directory controls, and supporting Multi-Factor Authentication (MFA), Conditional Access Policies, and other hardening measures for a centralized and secure access solution.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.1", + "Description": "Ensure that Microsoft Entra authentication is Configured for SQL Servers", + "Checks": [ + "sqlserver_azuread_administrator_enabled" + ], + "Attributes": [ + { + "Title": "Microsoft Entra authentication is Configured for SQL Servers", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Use Microsoft Entra authentication for SQL Database to centralize identity and credential management, enhancing security and simplifying access control. By leveraging Microsoft Entra ID, organizations can manage database users, permissions, and authentication policies in a single location, reducing complexity and improving security.", + "AdditionalInformation": "Microsoft Entra authentication eliminates the need for separate SQL authentication, preventing identity sprawl and simplifying password management. It enables centralized permission management, supports token-based authentication, integrates with Active Directory Federation Services (ADFS), and enhances security with Multi-Factor Authentication (MFA). Using Entra ID authentication also eliminates the need to store passwords, enabling secure, modern authentication methods while ensuring seamless access control for users and applications.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.2", + "Description": "Ensure 'Allow public access from any Azure service within Azure to this server' for PostgreSQL flexible server is disabled ", + "Checks": [ + "postgresql_flexible_server_allow_access_services_disabled" + ], + "Attributes": [ + { + "Title": "Allow public access from any Azure service within Azure to this server' for PostgreSQL flexible server is disabled ", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Disable access from Azure services to PostgreSQL flexible servers to restrict inbound connections and enhance security.", + "AdditionalInformation": "Allowing access from all Azure services bypasses firewall restrictions and permits connections from any Azure resource, including those outside your subscription. This can expose the database to unauthorized access and security risks. Instead, configure firewall rules or Virtual Network (VNet) rules to allow only specific, trusted network ranges, ensuring tighter access control.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.3", + "Description": "Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks", + "Checks": [ + "cosmosdb_account_firewall_use_selected_networks" + ], + "Attributes": [ + { + "Title": "Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Restrict Cosmos DB access to whitelisted networks to minimize exposure and reduce potential attack vectors.", + "AdditionalInformation": "Limiting Cosmos DB communication to specific trusted networks prevents unauthorized access from unapproved sources, including the public internet. This enhances security by reducing the attack surface and ensuring only designated networks can interact with the database.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.4", + "Description": "Ensure That Private Endpoints Are Used Where Possible", + "Checks": [ + "cosmosdb_account_use_private_endpoints" + ], + "Attributes": [ + { + "Title": "Private Endpoints Are Used", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Use private endpoints for Cosmos DB to restrict network traffic to approved sources, ensuring secure and private communication.", + "AdditionalInformation": "For sensitive data, private endpoints provide granular control over which services can access Cosmos DB, preventing exposure to unauthorized networks. This setup ensures that all traffic remains within a private network, reducing security risks and enhancing data protection.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.5", + "Description": "Use Entra ID Client Authentication and Azure RBAC where possible", + "Checks": [ + "cosmosdb_account_use_aad_and_rbac" + ], + "Attributes": [ + { + "Title": "Entra ID Client Authentication and Azure RBAC where possible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Use Microsoft Entra ID for Cosmos DB client authentication, leveraging Azure RBAC for enhanced security, centralized management, and MFA support.", + "AdditionalInformation": "Entra ID authentication is significantly more secure than token-based authentication, as tokens must be stored persistently on the client, increasing the risk of compromise. Entra ID eliminates this risk by securely handling credentials, integrating seamlessly with Azure RBAC, and supporting multi-factor authentication (MFA) for stronger access control.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.6", + "Description": "Ensure that 'Public Network Access' is 'Disabled' for storage accounts", + "Checks": [ + "storage_blob_public_access_level_is_disabled" + ], + "Attributes": [ + { + "Title": "Public Network Access' is 'Disabled' for storage accounts", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Disable public network access for Azure Storage accounts, ensuring that access settings for individual containers cannot override this restriction. This applies to Azure Resource Manager deployment model storage accounts, as classic deployment model accounts will be retired by August 31, 2024.", + "AdditionalInformation": "By default, Azure Storage accounts allow users with appropriate permissions to enable public access to containers and blobs, granting read-only access without requiring authentication. To minimize the risk of unauthorized data exposure, public access should be restricted unless explicitly required. Instead, use Azure AD RBAC or shared access signatures (SAS) to grant controlled and time-limited access to storage resources.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.7", + "Description": "Ensure Default Network Access Rule for Storage Accounts is Set to Deny", + "Checks": [ + "storage_default_network_access_rule_is_denied" + ], + "Attributes": [ + { + "Title": "Default Network Access Rule for Storage Accounts is Set to Deny", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Restricting default network access enhances security by preventing unrestricted connections to Azure Storage accounts. By default, storage accounts accept connections from any network, so access should be limited to selected networks by modifying the default configuration.", + "AdditionalInformation": "Storage accounts should deny access from all networks by default, except for explicitly allowed Azure Virtual Networks or specific IP address ranges. This approach creates a secure network boundary, ensuring only authorized applications can connect. Even when network rules allow access, proper authentication (via access keys or SAS tokens) is still required, adding an extra layer of security.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.8", + "Description": "Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access", + "Checks": [ + "storage_ensure_azure_services_are_trusted_to_access_is_enabled" + ], + "Attributes": [ + { + "Title": "Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "This recommendation assumes that public network access is set to “Enabled from selected virtual networks and IP addresses” and that the default network access rule for storage accounts is set to deny. Some Azure services require access to storage accounts from networks that cannot be explicitly granted permissions through network rules. To allow these services to function properly, enable the trusted Azure services exception, which allows selected Azure services to bypass network restrictions while still enforcing strong authentication.", + "AdditionalInformation": "Enabling firewall rules on a storage account blocks access to all incoming requests, including those from other Azure services. Allowing access to trusted Azure services ensures that essential Azure functions, such as Azure Backup, Event Grid, Monitor, and Site Recovery, can interact with storage accounts securely without exposing them to broader public access.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.9", + "Description": "Ensure Private Endpoints are used to access Storage Accounts", + "Checks": [ + "storage_ensure_private_endpoints_in_storage_accounts" + ], + "Attributes": [ + { + "Title": "Private Endpoint used to access Storage Accounts", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Use private endpoints for Azure Storage accounts to enable secure, encrypted access over a Private Link. Private endpoints assign an IP address from the Virtual Network (VNet) for each service, ensuring that network traffic remains isolated and encrypted within the VNet. This configuration helps segment network traffic, preventing external access while allowing secure communication between services. Additionally, VNets can extend addressing spaces or act as secure tunnels over public networks, connecting remote infrastructures securely.", + "AdditionalInformation": "Encrypting traffic between services protects sensitive data from interception and unauthorized access. Using private endpoints ensures that data remains within a controlled network environment, reducing exposure to external threats and enhancing overall security posture.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.2.10", + "Description": "Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0", + "Checks": [ + "sqlserver_unrestricted_inbound_access" + ], + "Attributes": [ + { + "Title": "Azure SQL Databases do not allow ingress from 0.0.0.0/0", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Ensure that Azure SQL Databases do not allow ingress from 0.0.0.0/0 (ANY IP), as this would expose them to the public internet. Azure SQL Server includes a firewall that blocks unauthorized connections by default, but it allows defining more granular IP address rules to restrict access. Allowing 0.0.0.0/0 effectively grants open access, increasing security risks.", + "AdditionalInformation": "Leaving Azure SQL firewall rules open to ANY IP significantly increases the attack surface, making databases vulnerable to brute-force attacks and unauthorized access. Instead, firewall rules should be restricted to specific, trusted IP ranges from known datacenters or internal resources. Additionally, enabling Allow Azure services and resources to access this server could allow access from outside your organization’s subscription or region, potentially bypassing SQL Server’s network ACLs and exposing the database to malicious activity.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.3.1", + "Description": "Ensure App Service Authentication is set up for apps in Azure App Service", + "Checks": [ + "app_ensure_auth_is_set_up" + ], + "Attributes": [ + { + "Title": "App Service Authentication is set up for apps in Azure App Service", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Enable Azure App Service Authentication to restrict anonymous HTTP requests and enforce authentication using identity providers before requests reach the application.", + "AdditionalInformation": "Enabling App Service Authentication ensures that all incoming HTTP requests are validated and authenticated before being processed by the application. It integrates with Microsoft Entra ID, Google, Facebook, Microsoft Accounts, and Twitter to manage authentication, token validation, and session handling. Additionally, disabling HTTP Basic Authentication helps mitigate risks from legacy authentication methods, strengthening application security.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.3.2", + "Description": "Ensure 'FTP State' is set to 'FTPS Only' or 'Disabled' ", + "Checks": [ + "app_ftp_deployment_disabled" + ], + "Attributes": [ + { + "Title": "FTP State' is set to 'FTPS Only' or 'Disabled' ", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Ensure that FTP access is disabled for Azure App Services, or if required, enforce FTPS (FTP over SSL/TLS) for secure authentication and data transmission.", + "AdditionalInformation": "FTP transmits data, including credentials, in plaintext, making it vulnerable to interception, credential theft, and data exfiltration. Requiring FTPS ensures that all FTP connections are encrypted, reducing the risk of unauthorized access, persistence, and lateral movement within the environment. If FTP is not needed, disabling it entirely enhances security by eliminating an unnecessary attack vector.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.1.1", + "Description": "Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL flexible server", + "Checks": [ + "postgresql_flexible_server_log_checkpoints_on" + ], + "Attributes": [ + { + "Title": "log_checkpoints' is set to 'ON' for PostgreSQL flexible server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable log_checkpoints on PostgreSQL flexible servers to log checkpoint activity, generating query and error logs that aid in monitoring and troubleshooting database performance.", + "AdditionalInformation": "Logging checkpoints helps track database activity, errors, and performance issues, providing valuable insights for troubleshooting and optimization. While transaction logs remain inaccessible, query and error logs allow identification and resolution of configuration errors and inefficiencies, improving database reliability and performance.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.2", + "Description": "Ensure server parameter 'connection_throttle.enable' is set to 'ON' for PostgreSQL flexible server", + "Checks": [ + "postgresql_flexible_server_connection_throttling_on" + ], + "Attributes": [ + { + "Title": "connection_throttle.enable' is set to 'ON' for PostgreSQL flexible server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable connection throttling on PostgreSQL flexible servers to regulate concurrent connections and generate logs for monitoring and troubleshooting.", + "AdditionalInformation": "Connection throttling helps prevent Denial of Service (DoS) attacks by limiting excessive connections that could exhaust resources. It also protects against system failures or degraded performance caused by high user loads. Query and error logs provide insights into connection issues, enabling faster troubleshooting and performance optimization.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.3", + "Description": "Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL single server", + "Checks": [ + "postgresql_flexible_server_log_connections_on" + ], + "Attributes": [ + { + "Title": "log_connections' is set to 'ON' for PostgreSQL single server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable log_connections on PostgreSQL Single Servers to record connection attempts and authentication events for security monitoring and auditing. (Note: This recommendation applies only to Single Server, as Azure PostgreSQL Single Server is planned for retirement.)", + "AdditionalInformation": "Logging connection attempts helps detect unauthorized access, failed authentication attempts, and potential security threats. These logs provide valuable insights for troubleshooting, auditing, and identifying suspicious activities, enhancing overall database security and monitoring.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.4", + "Description": "Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL single server", + "Checks": [ + "postgresql_flexible_server_log_disconnections_on" + ], + "Attributes": [ + { + "Title": "log_disconnections' is set to 'ON' for PostgreSQL single server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable log_disconnections on PostgreSQL Servers to record session termination events, including session duration. (Note: This recommendation applies only to Single Server, as Azure PostgreSQL Single Server is planned for retirement.)", + "AdditionalInformation": "Logging disconnections provides visibility into session activity and duration, helping to analyze user behavior, detect anomalies, and troubleshoot performance issues. These logs contribute to audit trails, security monitoring, and database performance optimization.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.5", + "Description": "Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL flexible server", + "Checks": [ + "mysql_flexible_server_audit_log_enabled" + ], + "Attributes": [ + { + "Title": "audit_log_enabled' is set to 'ON' for MySQL flexible server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable audit_log_enabled on MySQL flexible servers to capture logs for connection attempts, DDL/DML activity, and other database events for security and monitoring purposes.", + "AdditionalInformation": "Logging database activity helps detect unauthorized access, troubleshoot issues, and analyze performance bottlenecks. Enabling audit logs enhances security visibility, compliance monitoring, and incident response by providing valuable insights into database operations.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.6", + "Description": "Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL flexible server", + "Checks": [ + "mysql_flexible_server_audit_log_connection_activated" + ], + "Attributes": [ + { + "Title": "audit_log_events' has 'CONNECTION' set for MySQL flexible server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Configure audit_log_events on MySQL flexible servers to include CONNECTION events, ensuring that successful and failed connection attempts are logged.", + "AdditionalInformation": "Logging CONNECTION events provides visibility into authentication attempts, helping to detect unauthorized access, troubleshoot issues, and optimize database performance. These logs are essential for security monitoring, compliance, and identifying potential misconfigurations or attack attempts.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.7", + "Description": "Ensure that logging for Azure Key Vault is 'Enabled' ", + "Checks": [ + "keyvault_logging_enabled" + ], + "Attributes": [ + { + "Title": "Logging for Azure Keyvault enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable AuditEvent logging for Azure Key Vault to track and log interactions with keys, certificates, and other sensitive information.", + "AdditionalInformation": "Logging Key Vault access events provides an audit trail that helps monitor who accessed the vault, when, and how. This enhances security, compliance, and incident response by ensuring logs are stored in a designated Azure Storage account or Log Analytics workspace, allowing centralized monitoring across multiple Key Vaults.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.8", + "Description": "Ensure that Network Security Group Flow logs are captured and sent to Log Analytics", + "Checks": [ + "network_flow_log_captured_sent" + ], + "Attributes": [ + { + "Title": "Network Security Group Flow logs are captured and sent to Log Analytics", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Ensure that network flow logs are collected and sent to a central Log Analytics workspace for monitoring and analysis.", + "AdditionalInformation": "Capturing network flow logs provides visibility into traffic patterns across your network, helping detect anomalies, potential lateral movement, and security threats. These logs integrate with Azure Monitor and Azure Sentinel, enabling advanced analytics and visualization for improved network security and incident response.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.9", + "Description": "Ensure that logging for Azure AppService 'HTTP logs' is enabled", + "Checks": [ + "app_http_logs_enabled" + ], + "Attributes": [ + { + "Title": "Logging for Azure AppService 'HTTP logs' is enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enable AppServiceHTTPLogs for Azure App Service instances to capture and centrally log all HTTP requests.", + "AdditionalInformation": "Logging web requests provides critical data for security monitoring and incident response. Captured logs can be ingested into a SIEM or central log aggregation system, helping security analysts detect anomalies, investigate threats, and enhance application security.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure that 'Auditing' Retention is 'greater than 90 days'", + "Checks": [ + "sqlserver_auditing_retention_90_days" + ], + "Attributes": [ + { + "Title": "Auditing' Retention is 'greater than 90 days'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "Configure SQL Server Audit Retention to retain logs for more than 90 days to ensure long-term visibility into database activity and security events.", + "AdditionalInformation": "Maintaining audit logs for over 90 days helps detect anomalies, security breaches, and unauthorized access. Longer retention periods allow organizations to analyze historical data, support compliance requirements, and strengthen forensic investigations.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'", + "Checks": [ + "network_flow_log_more_than_90_days" + ], + "Attributes": [ + { + "Title": "Network Security Group Flow Log retention period is 'greater than 90 days'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "Enable Network Security Group (NSG) Flow Logs and configure the retention period to at least 90 days to capture and store IP traffic data for security monitoring and analysis.", + "AdditionalInformation": "NSG Flow Logs provide visibility into network traffic, helping detect anomalies, unauthorized access, and potential security breaches. Retaining logs for at least 90 days ensures that historical data is available for incident investigation, compliance, and forensic analysis, strengthening overall network security monitoring.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.2.2", + "Description": "Ensure server parameter 'logfiles.retention_days' is greater than 3 days for PostgreSQL flexible server", + "Checks": [ + "postgresql_flexible_server_log_retention_days_greater_3" + ], + "Attributes": [ + { + "Title": "logfiles.retention_days' is greater than 3 days for PostgreSQL flexible server", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "Ensure that logfiles.retention_days on PostgreSQL flexible servers is set to an appropriate value to maintain access to historical logs for monitoring and troubleshooting.", + "AdditionalInformation": "Setting an appropriate log retention period ensures that query and error logs are available for diagnosing configuration issues, troubleshooting errors, and optimizing performance. Retaining logs for a sufficient duration supports security analysis, compliance requirements, and operational debugging while preventing unnecessary storage consumption.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.2.3", + "Description": "Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs", + "Checks": [ + "monitor_diagnostic_settings_exists" + ], + "Attributes": [ + { + "Title": "Diagnostic Setting' exists for Subscription Activity Logs", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "Enable Diagnostic Settings to export activity logs for all appropriate resources within a subscription, ensuring long-term visibility into security and operational events.", + "AdditionalInformation": "By default, logs are retained for only 90 days. Configuring diagnostic settings allows logs to be exported and stored for extended periods, enabling security analysis, compliance monitoring, and forensic investigations within an Azure subscription.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.1", + "Description": "Ensure that 'Auditing' is set to 'On' ", + "Checks": [ + "sqlserver_auditing_enabled" + ], + "Attributes": [ + { + "Title": "Auditing' is set to 'On'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Enable auditing on Azure SQL Servers to track and log database events for security and compliance purposes.", + "AdditionalInformation": "Auditing at the server level ensures that all existing and newly created databases inherit auditing policies, providing consistent monitoring across the SQL environment. It does not override database-level auditing policies but complements them. Audit logs are stored in Azure Storage, helping organizations maintain regulatory compliance, monitor database activity, and detect anomalies that may indicate security threats or operational concerns.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.10", + "Description": "Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule", + "Checks": [ + "monitor_alert_delete_sqlserver_fr" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Delete SQL Server Firewall Rule", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Delete SQL Server Firewall Rule event to monitor and track firewall rule removals in SQL Server.", + "AdditionalInformation": "Monitoring firewall rule deletions helps detect unauthorized or accidental changes that could expose the database to security risks. Timely alerts ensure quick detection and response to prevent unauthorized network access and maintain a secure SQL environment.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.11", + "Description": "Ensure that Activity Log Alert exists for Create or Update Public IP Address rule", + "Checks": [ + "monitor_alert_create_update_public_ip_address_rule" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Create or Update Public IP Address rule", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Create or Update Public IP Address event to monitor changes in public IP configurations.", + "AdditionalInformation": "Tracking public IP address modifications provides visibility into network access changes, helping detect unauthorized or misconfigured public exposure. Timely alerts enable faster detection and response to potential security risks, ensuring a controlled and secure network environment.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.3.12", + "Description": "Ensure that Activity Log Alert exists for Delete Public IP Address rule", + "Checks": [ + "monitor_alert_delete_public_ip_address_rule" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Delete Public IP Address rule", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Delete Public IP Address event to monitor and track the removal of public IP addresses.", + "AdditionalInformation": "Monitoring public IP deletions helps detect unauthorized or accidental changes that could impact network accessibility or security. Timely alerts enable quick investigation and response, ensuring that critical network configurations remain intact and secure.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.13", + "Description": "Ensure Application Insights are Configured", + "Checks": [ + "appinsights_ensure_is_configured" + ], + "Attributes": [ + { + "Title": "Application Insights are Configured", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Application Insights in Azure serves as an Application Performance Monitoring (APM) solution, providing valuable insights into application performance, telemetry data, and trace logs. It helps organizations monitor application health and troubleshoot incidents efficiently.", + "AdditionalInformation": "Enabling Application Insights enhances security monitoring and performance optimization by collecting metrics, telemetry, and trace logs. These logs aid in proactive performance tuning to reduce costs and support incident response by helping identify the root cause of potential security or operational issues. Integrating Application Insights into a broader logging and monitoring strategy strengthens an organization’s overall observability and security posture.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.14", + "Description": "Ensure that Network Watcher is 'Enabled' for Azure Regions that are in use", + "Checks": [ + "network_watcher_enabled" + ], + "Attributes": [ + { + "Title": "Network Watcher 'Enabled' for used Regions", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Enable Network Watcher for all Azure regions within your subscription to monitor and diagnose network activity.", + "AdditionalInformation": "Network Watcher provides network diagnostic and visualization tools that help organizations analyze traffic, troubleshoot connectivity issues, and detect anomalies. Enabling it enhances network visibility, security monitoring, and operational insights across Azure environments.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.15", + "Description": "Ensure that Endpoint Protection for all Virtual Machines is installed", + "Checks": [ + "defender_assessments_vm_endpoint_protection_installed" + ], + "Attributes": [ + { + "Title": "Endpoint Protection for all Virtual Machines is installed", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Ensure endpoint protection is installed on all Azure Virtual Machines (VMs) to provide real-time security monitoring and threat detection.", + "AdditionalInformation": "Endpoint protection helps detect and remove malware, viruses, and other security threats, protecting VMs from compromise and unauthorized access. It also provides configurable alerts for suspicious activity, enhancing security monitoring and incident response across Azure environments.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.16", + "Description": "Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'", + "Checks": [ + "defender_ensure_system_updates_are_applied" + ], + "Attributes": [ + { + "Title": "Defender Recommendation for 'Apply system updates' status is 'Completed'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Ensure that all Windows and Linux Virtual Machines (VMs) have the latest OS patches and security updates applied to mitigate vulnerabilities and improve system stability.", + "AdditionalInformation": "Keeping VMs updated helps address security vulnerabilities, bug fixes, and stability improvements. Microsoft Defender for Cloud continuously checks for missing critical and security updates using Windows Update, WSUS, or Linux package managers. Applying recommended updates reduces the risk of exploits, malware, and performance issues, ensuring a secure and resilient cloud environment.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.17", + "Description": "Ensure that Microsoft Cloud Security Benchmark policies are not set to 'Disabled'", + "Checks": [ + "policy_ensure_asc_enforcement_enabled" + ], + "Attributes": [ + { + "Title": "Microsoft Cloud Security Benchmark policies are not set to 'Disabled'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Ensure that all Microsoft Cloud Security Benchmark (MCSB) policies are enabled to effectively evaluate resource configurations against best practice security recommendations.", + "AdditionalInformation": "The MCSB Policy Initiative enforces security best practices and helps ensure compliance with organizational and regulatory requirements. If a policy’s Effect is set to Disabled, it will not be evaluated, potentially preventing administrators from detecting security misconfigurations. Keeping all MCSB policies enabled allows Microsoft Defender for Cloud to assess relevant resources and provide actionable security insights to strengthen cloud security.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.3.18", + "Description": "Ensure That 'All users with the following roles' is set to 'Owner'", + "Checks": [ + "defender_ensure_notify_emails_to_owners" + ], + "Attributes": [ + { + "Title": "All users with the following roles' is set to 'Owner'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Ensure that security alert emails are enabled for subscription owners to receive notifications about potential security threats and vulnerabilities.", + "AdditionalInformation": "Enabling security alert emails ensures that subscription owners are promptly informed of security incidents, threats, or misconfigurations detected by Microsoft Defender for Cloud. Timely notifications allow administrators to take immediate action, mitigate risks, and maintain a strong security posture within the Azure environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.3.19", + "Description": "Ensure 'Additional email addresses' is Configured with a Security Contact Email", + "Checks": [ + "defender_additional_email_configured_with_a_security_contact" + ], + "Attributes": [ + { + "Title": "Additional email addresses' is Configured with a Security Contact Email", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Configure Microsoft Defender for Cloud to send high-severity security alerts to a designated security contact email in addition to the subscription owner.", + "AdditionalInformation": "By default, Microsoft Defender for Cloud notifies only subscription owners of critical security alerts. Adding a security contact email ensures that the security team is promptly informed of potential threats, allowing for faster response and risk mitigation to maintain a secure Azure environment.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.2", + "Description": "Ensure Diagnostic Setting captures appropriate categories", + "Checks": [ + "monitor_diagnostic_setting_with_appropriate_categories" + ], + "Attributes": [ + { + "Title": "Diagnostic Setting captures appropriate categories", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Ensure that Diagnostic Settings are configured to log relevant control and management plane activities for enhanced visibility and security monitoring. (Note: A Diagnostic Setting must exist for this configuration to be available.)", + "AdditionalInformation": "Diagnostic settings determine how logs are exported and stored. Capturing logs from the control and management plane enables proper alerting, monitoring, and analysis of administrative actions, helping to detect unauthorized changes and security threats.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.20", + "Description": "Ensure That 'Notify about alerts with the following severity' is Set to 'High'", + "Checks": [ + "defender_ensure_notify_alerts_severity_is_high" + ], + "Attributes": [ + { + "Title": "Notify about alerts with the following severity' is Set to 'High'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Enable security alert emails to notify the subscription owner or designated security contacts about potential security threats.", + "AdditionalInformation": "Ensuring security alerts are sent to the appropriate personnel allows for timely detection and response to security incidents. This helps mitigate risks by ensuring that critical threats and vulnerabilities are addressed promptly, improving the overall security posture of the Azure environment.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.21", + "Description": "Ensure That Microsoft Defender for DNS Is Set To 'On'", + "Checks": [ + "defender_ensure_defender_for_dns_is_on" + ], + "Attributes": [ + { + "Title": "Defender for DNS Is Set To 'On'", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Enable Microsoft Defender for DNS to monitor and scan outgoing DNS traffic within a subscription for potential security threats. (Note: As of August 1, 2023, new subscribers receive DNS threat alerts as part of Defender for Servers P2.)", + "AdditionalInformation": "Defender for DNS analyzes DNS queries against a dynamic threat intelligence list to detect potential malicious activity, compromised services, or security breaches. Monitoring DNS lookups helps identify and prevent threats such as data exfiltration, command and control (C2) communications, and phishing attacks, improving overall network security.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.3", + "Description": "Ensure that Activity Log Alert exists for Create Policy Assignment", + "Checks": [ + "monitor_alert_create_policy_assignment" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Create Policy Assignment", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an activity log alert for the Create Policy Assignment event to track changes in Azure Policy assignments.", + "AdditionalInformation": "Monitoring policy assignment events helps detect unauthorized or unintended changes in Azure policies, providing greater visibility and reducing the time required to identify and respond to policy modifications.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.4", + "Description": "Ensure that Activity Log Alert exists for Delete Policy Assignment", + "Checks": [ + "monitor_alert_delete_policy_assignment" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Delete Policy Assignment", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an activity log alert for the Delete Policy Assignment event to monitor and track policy removal activities in Azure Policy assignments.", + "AdditionalInformation": "Monitoring policy deletions helps detect unauthorized or unintended changes, ensuring policy integrity and reducing the time required to identify and respond to security or compliance violations.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.5", + "Description": "Ensure that Activity Log Alert exists for Create or Update Network Security Group", + "Checks": [ + "monitor_alert_create_update_nsg" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Create or Update Network Security Group", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Create or Update Network Security Group (NSG) event to track changes in network security configurations.", + "AdditionalInformation": "Monitoring NSG creation and updates provides visibility into network access changes, helping to detect unauthorized modifications and identify potential security risks in a timely manner.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.6", + "Description": "Ensure that Activity Log Alert exists for Delete Network Security Group", + "Checks": [ + "monitor_alert_delete_nsg" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Delete Network Security Group", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Delete Network Security Group (NSG) event to monitor and track network security group removals.", + "AdditionalInformation": "Monitoring NSG deletions provides visibility into network access changes, helping to detect unauthorized modifications and identify potential security threats before they impact the environment.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.7", + "Description": "Ensure that Activity Log Alert exists for Create or Update Security Solution", + "Checks": [ + "monitor_alert_create_update_security_solution" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Create or Update Security Solution", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Create or Update Security Solution event to track modifications to security solutions in your environment.", + "AdditionalInformation": "Monitoring security solution changes provides visibility into updates, additions, or modifications to active security configurations. This helps detect unauthorized changes or suspicious activity and ensures that security controls remain properly configured.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.3.8", + "Description": "Ensure that Activity Log Alert exists for Delete Security Solution", + "Checks": [ + "monitor_alert_delete_security_solution" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Delete Security Solution", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Delete Security Solution event to monitor and track the removal of security solutions in your environment.", + "AdditionalInformation": "Monitoring security solution deletions helps detect unauthorized removals or suspicious activity, ensuring that critical security controls are not accidentally or maliciously disabled. This improves security visibility and helps maintain a strong security posture.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.9", + "Description": "Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule", + "Checks": [ + "monitor_alert_create_update_sqlserver_fr" + ], + "Attributes": [ + { + "Title": "Activity Log Alert exists for Create or Update SQL Server Firewall Rule", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Create an Activity Log Alert for the Create or Update SQL Server Firewall Rule event to track changes in SQL Server firewall configurations.", + "AdditionalInformation": "Monitoring firewall rule modifications provides visibility into network access changes, helping detect unauthorized updates that could expose the database to security risks. Timely alerts can reduce the time needed to identify and respond to suspicious activity, ensuring a secure SQL environment.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "4.1.1", + "Description": "Ensure server parameter 'require_secure_transport' is set to 'ON' for PostgreSQL flexible server", + "Checks": [ + "postgresql_flexible_server_enforce_ssl_enabled" + ], + "Attributes": [ + { + "Title": "require_secure_transport' is set to 'ON' for PostgreSQL flexible server", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Enable require_secure_transport on PostgreSQL flexible servers to enforce SSL connections between the database server and client applications, ensuring encrypted communication.", + "AdditionalInformation": "Requiring SSL encryption helps protect data in transit from man-in-the-middle attacks by securing the connection between the database server and client applications. Enforcing secure transport prevents unauthorized access and strengthens data integrity and confidentiality.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.2", + "Description": "Ensure server parameter 'require_secure_transport' is set to 'ON' for MySQL flexible server", + "Checks": [ + "postgresql_flexible_server_enforce_ssl_enabled" + ], + "Attributes": [ + { + "Title": "require_secure_transport' is set to 'ON' for MySQL flexible server", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Enable require_secure_transport on MySQL flexible servers to enforce SSL encryption between the database server and client applications, ensuring secure communication.", + "AdditionalInformation": "Requiring SSL connectivity protects data in transit from man-in-the-middle attacks by encrypting communication between client applications and the database server. Enforcing secure transport helps prevent unauthorized access and data interception, strengthening the overall security posture of the database.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.3", + "Description": "Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2'", + "Checks": [ + "storage_ensure_minimum_tls_version_12" + ], + "Attributes": [ + { + "Title": "Minimum TLS version' for storage accounts is set to 'Version 1.2'", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Ensure that the minimum TLS version for Azure Storage is set to TLS 1.2 or higher to mitigate security vulnerabilities associated with older TLS versions.", + "AdditionalInformation": "TLS 1.0 is outdated and has known security vulnerabilities that can expose data in transit to attacks and interception. Upgrading to TLS 1.2 or later enhances encryption security, ensuring secure communication between clients and Azure Storage while reducing the risk of data compromise.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "4.1.4", + "Description": "Ensure 'HTTPS Only' is set to `On`", + "Checks": [ + "app_ensure_http_is_redirected_to_https" + ], + "Attributes": [ + { + "Title": "`HTTPS Only' is set to `On`", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Configure Azure App Service to enforce HTTPS-only traffic, ensuring that all HTTP requests are automatically redirected to HTTPS for secure communication.", + "AdditionalInformation": "Enforcing HTTPS protects data in transit by using TLS/SSL encryption, preventing man-in-the-middle attacks and ensuring secure authentication. Redirecting non-secure HTTP traffic to HTTPS enhances the confidentiality and integrity of application communications, reducing exposure to security vulnerabilities.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.5", + "Description": "Ensure Web App is using the latest version of TLS encryption", + "Checks": [ + "app_minimum_tls_version_12" + ], + "Attributes": [ + { + "Title": "Web App is using the latest version of TLS encryption", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Ensure that Azure App Service is configured to use TLS 1.2 or higher to secure data transmission and align with industry security standards.", + "AdditionalInformation": "TLS 1.0 and 1.1 are outdated protocols with known vulnerabilities that expose web applications to security threats, including data interception and man-in-the-middle attacks. TLS 1.2 is the recommended encryption standard by industry frameworks such as PCI DSS, providing stronger encryption and improved security for web app connections.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.6", + "Description": "Ensure that 'HTTP20enabled' is set to 'true'", + "Checks": [ + "app_ensure_using_http20" + ], + "Attributes": [ + { + "Title": "HTTP20enabled' is set to 'true'", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Ensure that Azure App Service is configured to use the latest supported HTTP version to benefit from security improvements, performance enhancements, and new functionalities.", + "AdditionalInformation": "Newer HTTP versions provide security enhancements, performance optimizations, and better resource management. HTTP/2, for example, improves efficiency by addressing issues such as head-of-line blocking, header compression, and request prioritization. Keeping apps updated to the latest HTTP version ensures they leverage modern security protocols and enhanced data transmission capabilities while maintaining compatibility and performance standards.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "4.2.1", + "Description": "Ensure Storage for Critical Data are Encrypted with Customer Managed Keys (CMK)", + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys" + ], + "Attributes": [ + { + "Title": "Storage for Critical Data are Encrypted CMK", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Enable encryption at rest using Customer Managed Keys (CMK) instead of Microsoft Managed Keys to maintain greater control over sensitive data encryption in Azure Storage accounts.", + "AdditionalInformation": "By default, Azure encrypts all storage resources (blobs, disks, files, queues, and tables) using Microsoft Managed Keys. However, using Customer Managed Keys (CMK) allows organizations to control, manage, and rotate their encryption keys through Azure Key Vault, ensuring compliance with security policies. CMKs also support automatic key version updates for enhanced security. Since this recommendation applies specifically to storage accounts holding critical data, its assessment remains manual rather than automated.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.2.2", + "Description": "Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key", + "Checks": [ + "sqlserver_tde_encrypted_with_cmk" + ], + "Attributes": [ + { + "Title": "SQL server's TDE protector is encrypted with CMK", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Enable Transparent Data Encryption (TDE) with Customer-Managed Keys (CMK) to enhance control, security, and separation of duties over the TDE Protector. TDE encrypts data at rest using a database encryption key (DEK). Traditionally, DEKs were protected by Azure SQL Service-managed certificates, but with Customer-Managed Key support, the DEK can now be secured using an asymmetric key stored in Azure Key Vault. Azure Key Vault provides centralized key management, FIPS 140-2 Level 2 validated HSMs, and additional security through key and data separation. Based on business needs and data sensitivity, organizations should use Customer-Managed Keys for TDE encryption.", + "AdditionalInformation": "Using Customer-Managed Keys for TDE gives organizations full control over encryption keys, including who can access them and when. Azure Key Vault serves as a secure external key management system, ensuring that TDE encryption keys remain protected from unauthorized access. When configured, the asymmetric key is set at the server level and inherited by all databases under that server, providing consistent encryption management across the environment.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.2.3", + "Description": "Ensure that 'Data encryption' is set to 'On' on a SQL Database", + "Checks": [ + "sqlserver_tde_encryption_enabled" + ], + "Attributes": [ + { + "Title": "Data encryption' is set to 'On' on a SQL Database", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Enable Transparent Data Encryption (TDE) on all Azure SQL Servers to ensure real-time encryption and decryption of databases, backups, and transaction logs at rest. TDE operates seamlessly without requiring modifications to applications.", + "AdditionalInformation": "TDE helps protect Azure SQL Databases from unauthorized access and malicious activity by encrypting data at rest. This ensures that database files, backups, and logs remain secure, reducing the risk of data breaches while maintaining operational transparency.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "4.2.4", + "Description": "Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key (CMK)", + "Checks": [ + "monitor_storage_account_with_activity_logs_cmk_encrypted" + ], + "Attributes": [ + { + "Title": "Storage account with logs encrypted with CMK", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Configure storage accounts used for activity log exports to use Customer Managed Keys (CMK) for enhanced security and access control.", + "AdditionalInformation": "Using CMKs for log storage provides additional confidentiality controls, ensuring that only users with read access to the storage account and explicit decrypt permissions can access the logs. This enhances data security by restricting unauthorized access and strengthening compliance with encryption and access management policies.", + "LevelOfRisk": 3 + } + ] + } + ] +} diff --git a/prowler/compliance/gcp/prowler_threatscore_gcp.json b/prowler/compliance/gcp/prowler_threatscore_gcp.json new file mode 100644 index 0000000000..2ccb7e7add --- /dev/null +++ b/prowler/compliance/gcp/prowler_threatscore_gcp.json @@ -0,0 +1,977 @@ +{ + "Framework": "ProwlerThreatScore", + "Version": "1.0", + "Provider": "GCP", + "Description": "Prowler ThreatScore Compliance Framework for GCP ensures that the GCP project is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + "Requirements": [ + { + "Id": "1.1.1", + "Description": "Ensure User-Managed/External Keys for Service Accounts Are Rotated Every 90 Days or Fewer", + "Checks": [ + "iam_sa_user_managed_key_rotate_90_days" + ], + "Attributes": [ + { + "Title": "User-Managed/External Keys for Service Accounts Are Rotated Every 90 Days or Fewer", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "Service account keys consist of a key ID (private_key_id) and a private key, which are used to authenticate programmatic requests to Google Cloud services. It is recommended to regularly rotate service account keys to enhance security and reduce the risk of unauthorized access.", + "AdditionalInformation": "Regularly rotating service account keys minimizes the risk of a compromised, lost, or stolen key being used to access cloud resources. Google-managed keys are automatically rotated daily for internal authentication, ensuring strong security. For user-managed (external) keys, users are responsible for key security, storage, and rotation. Since Google does not retain private keys once generated, proper key management practices must be followed. Google Cloud allows up to 10 external keys per service account, making it easier to rotate them without disruption. Implementing regular key rotation ensures that old keys are not left active, reducing the potential attack surface.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.1.2", + "Description": "Ensure API Keys Only Exist for Active Services", + "Checks": [ + "apikeys_key_exists" + ], + "Attributes": [ + { + "Title": "API Keys Only Exist for Active Services", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "API keys should only be used when no other authentication method is available, as they pose significant security risks. Unused API keys with active permissions may still exist within a project, potentially exposing resources to unauthorized access. It is recommended to use standard authentication flows such as OAuth 2.0 or service account authentication instead.", + "AdditionalInformation": "API keys are inherently insecure because they: Are simple encrypted strings that can be easily exposed in browsers, client-side applications, or devices. Do not authenticate users or applications making API requests. Can be accidentally leaked in logs, repositories, or web traffic.To enhance security, API keys should be avoided when possible, and unused keys should be deleted to minimize the risk of unauthorized access.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.1.3", + "Description": "Ensure API Keys Are Rotated Every 90 Days", + "Checks": [ + "apikeys_key_rotated_in_90_days" + ], + "Attributes": [ + { + "Title": "API Keys Are Rotated Every 90 Days", + "Section": "1. IAM", + "SubSection": "1.1 Authentication", + "AttributeDescription": "API keys should only be used when no other authentication method is available. If API keys are in use, it is recommended to rotate them every 90 days to minimize security risks.", + "AdditionalInformation": "API keys are inherently insecure because: They are simple encrypted strings that can be easily exposed. They do not authenticate users or applications making API requests. They are often accessible to clients, increasing the risk of theft and misuse. Unlike credentials with expiration policies, stolen API keys remain valid indefinitely unless revoked or regenerated. Regularly rotating API keys reduces the risk of unauthorized access by ensuring that compromised keys cannot be used for extended periods. To enhance security, API keys should be rotated every 90 days or as part of a proactive security policy.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.1", + "Description": "Ensure That There Are Only GCP-Managed Service Account Keys for Each Service Account", + "Checks": [ + "iam_sa_no_user_managed_keysiam_sa_no_user_managed_keys" + ], + "Attributes": [ + { + "Title": "Only GCP-Managed Service Account Keys for Each Service Account", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Service accounts should not use user-managed keys, as they introduce security risks and require manual management. Instead, use Google Cloud-managed keys, which are automatically rotated and secured by Google.", + "AdditionalInformation": "User-managed keys are downloadable and manually managed, making them vulnerable to leaks, mismanagement, and unauthorized access. In contrast, GCP-managed keys are non-downloadable, automatically rotated weekly, and securely handled by Google Cloud services like App Engine and Compute Engine. Managing user-generated keys requires key storage, distribution, rotation, revocation, and protectionall of which introduce potential security gaps. Common risks include keys being exposed in source code repositories, left in unsecured locations, or unintentionally shared. To minimize security risks, it is recommended to disable user-managed service account keys and rely on GCP-managed keys instead.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.2", + "Description": "Ensure That Service Account Has No Admin Privileges", + "Checks": [ + "iam_sa_no_administrative_privileges" + ], + "Attributes": [ + { + "Title": "SA Has No Admin Privileges", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "A service account is a special Google account assigned to an application or virtual machine (VM) rather than an individual user. It is used to authenticate API requests on behalf of the application. Service accounts should not be granted admin privileges to minimize security risks.", + "AdditionalInformation": "Service accounts control resource access based on their assigned roles. Granting admin privileges to a service account allows full control over applications or VMs, enabling actions like deletion, updates, and configuration changes without user intervention. This increases the risk of misconfigurations, privilege escalation, or potential security breaches. To follow the principle of least privilege, it is recommended to restrict admin access for service accounts and assign only the necessary permissions.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.3", + "Description": "Ensure That Cloud KMS Cryptokeys Are Not Anonymously or Publicly Accessible", + "Checks": [ + "kms_key_not_publicly_accessible" + ], + "Attributes": [ + { + "Title": "Cloud KMS Cryptokeys Are Not Anonymously or Publicly Accessible", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "The IAM policy on Cloud KMS cryptographic keys should not allow anonymous (allUsers) or public (allAuthenticatedUsers) access to prevent unauthorized key usage.", + "AdditionalInformation": "Granting permissions to allUsers or allAuthenticatedUsers allows anyone to access the cryptographic keys, which can lead to data exposure, unauthorized encryption/decryption operations, or potential key compromise. This is particularly critical if sensitive data is protected using these keys. To maintain data security and compliance, ensure that Cloud KMS cryptographic keys are only accessible to authorized users, groups, or service accounts and do not have public or anonymous access permissions.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.4", + "Description": "Ensure KMS Encryption Keys Are Rotated Within a Period of 90 Days", + "Checks": [ + "kms_key_rotation_enabled" + ], + "Attributes": [ + { + "Title": "KMS Encryption Keys Are Rotated Within a Period of 90 Days", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "Google Cloud Key Management Service (KMS) organizes cryptographic keys in a hierarchical structure to facilitate secure and efficient access control. Keys should be configured with a defined rotation schedule to ensure their cryptographic strength is maintained over time.", + "AdditionalInformation": "Key rotation ensures that new key versions are automatically generated at regular intervals, reducing the risk of key compromise and unauthorized access. The key material (actual encryption bits) changes over time, even though the keys logical identity remains the same. Since cryptographic keys protect sensitive data, setting a specific rotation period ensures that encrypted data remains secure, minimizes the impact of a potential key leak, and aligns with best security practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.5", + "Description": "Ensure That Separation of Duties Is Enforced While Assigning KMS Related Roles to Users", + "Checks": [ + "iam_role_kms_enforce_separation_of_duties" + ], + "Attributes": [ + { + "Title": "Separation of Duties Is Enforced While Assigning KMS Related Roles to Users", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "The principle of Separation of Duties should be enforced when assigning Google Cloud Key Management Service (KMS) roles to users. This prevents excessive privileges and reduces security risks.", + "AdditionalInformation": "The Cloud KMS Admin role grants the ability to create, delete, and manage keys, while the Cloud KMS CryptoKey Encrypter/Decrypter, Encrypter, and Decrypter roles control encryption and decryption of data. Granting both administrative and cryptographic privileges to the same user violates the Separation of Duties principle, potentially allowing unauthorized access to sensitive data. To mitigate risks and prevent privilege escalation, no user should hold the Cloud KMS Admin role along with any of the CryptoKey Encrypter/Decrypter roles. Enforcing Separation of Duties helps ensure secure key management and aligns with security best practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.2.6", + "Description": "Ensure API Keys Are Restricted to Only APIs That Application Needs Access", + "Checks": [ + "apikeys_api_restrictions_configured" + ], + "Attributes": [ + { + "Title": "API Keys Are Restricted to Only APIs That Application Needs Access", + "Section": "1. IAM", + "SubSection": "1.2 Authorization", + "AttributeDescription": "API keys should only be used when no other authentication method is available, as they pose a higher security risk due to their public visibility. To minimize exposure, API keys should be restricted to access only the specific APIs required by an application.", + "AdditionalInformation": "API keys present several security risks, including: They are simple encrypted strings that can be easily exposed in client-side applications or browsers. They do not authenticate the user or application making API requests. They are often accessible to clients, making them susceptible to discovery and theft. Google recommends using standard authentication methods instead of API keys whenever possible. However, in limited scenarios where API keys are necessary (e.g., mobile applications using Google Cloud Translation API without a backend server), restricting API key access to only the required APIs helps enforce least privilege access and reduces attack surfaces.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "1.3.1", + "Description": "Ensure That IAM Users Are Not Assigned the Service Account User or Service Account Token Creator Roles at Project Level", + "Checks": [ + "iam_no_service_roles_at_project_level" + ], + "Attributes": [ + { + "Title": "IAM Users Are Not Assigned the SA User or SA Token Creator Roles at Project Level", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "It is recommended to assign the Service Account User (iam.serviceAccountUser) and Service Account Token Creator (iam.serviceAccountTokenCreator) roles to users at the service account level rather than granting them project-wide access.", + "AdditionalInformation": "Service accounts are identities used by applications and virtual machines (VMs) to interact with Google Cloud APIs. They also function as resources with IAM policies defining who can use them. Granting service account permissions at the project level allows users to access all service accounts within the project, including any created in the future. This increases the risk of privilege escalation, as users with Compute Instance Admin or App Engine Deployer roles could execute code as a service account, gaining access to additional resources. To enforce the principle of least privilege, users should be assigned service account roles at the specific service account level rather than at the project level. This ensures that each user has access only to the necessary service accounts while preventing unintended privilege escalation.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.3.2", + "Description": "Ensure That Separation of Duties Is Enforced While Assigning Service Account Related Roles to Users", + "Checks": [ + "iam_role_kms_enforce_separation_of_duties" + ], + "Attributes": [ + { + "Title": "Separation of Duties Is Enforced While Assigning Service Account Related Roles to Users", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "It is recommended to enforce the principle of Separation of Duties when assigning service account-related IAM roles to users to prevent excessive privileges and security risks.", + "AdditionalInformation": "The Service Account Admin role allows a user to create, delete, and manage service accounts, while the Service Account User role allows a user to assign service accounts to applications or compute instances. Granting both roles to the same user violates the Separation of Duties principle, as it would allow an individual to create and assign service accounts, potentially leading to unauthorized access or privilege escalation. To minimize security risks, no user should be assigned both Service Account Admin and Service Account User roles simultaneously. Enforcing Separation of Duties ensures better access control, reduces the risk of privilege abuse, and aligns with security best practices.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.3.3", + "Description": "Ensure That Cloud Audit Logging Is Configured Properly", + "Checks": [ + "iam_audit_logs_enabled" + ], + "Attributes": [ + { + "Title": "Cloud Audit Logging Is Configured Properly", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Cloud Audit Logging should be configured to track all administrative activities and read/write access to user data. This ensures comprehensive visibility into who accessed or modified resources within a project, folder, or organization.", + "AdditionalInformation": "Cloud Audit Logging maintains two types of audit logs: 1. Admin Activity Logs Captures API calls and administrative actions that modify configurations or metadata. These logs are enabled by default and cannot be disabled. 2. Data Access Logs Tracks API calls that create, modify, or read user data. These logs are disabled by default and should be enabled for better monitoring. Data Access Logs provide three types of visibility: Admin Read Tracks metadata or configuration reads. Data Read Logs operations where user-provided data is accessed. Data Write Captures modifications to user-provided data.To ensure effective logging, it is recommended to: 1. Enable DATA_READ logs (for user activity tracking) and DATA_WRITE logs (to track modifications). 2. Apply audit logging to all supported services where Data Access logs are available. 3.Avoid exempting users from audit logs to maintain full tracking capabilities. Properly configuring Cloud Audit Logging helps strengthen security, detect unauthorized access, and ensure compliance with security policies.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.3.4", + "Description": "Ensure Log Metric Filter and Alerts Exist for Project Ownership Assignments/Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for Project Ownership Assignments/Changes", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "In order to prevent unnecessary project ownership assignments to users or service accounts and mitigate potential misuse of projects and resources, all role assignments to roles/Owner should be monitored. Users or service accounts assigned the roles/Owner primitive role are considered project owners. The Owner role grants full control over the project, including: full viewer permissions on all GCP services, permissions to modify the state of all services, manage roles and permissions for the project and its resources, and set up billing for the project. Granting the Owner role allows the member to modify the IAM policy, which contains sensitive access control data. To minimize security risks, the Owner role should only be assigned when strictly necessary, and the number of users with this role should be kept to a minimum.", + "AdditionalInformation": "Project ownership has the highest level of privileges within a project, making it a high-risk role if misused. To reduce potential security risks, all project ownership assignments and changes should be monitored and alerted to security teams or relevant recipients. Critical events to monitor include: sending project ownership invitations, acceptance or rejection of ownership invites, assigning the roles/Owner role to a user or service account, and removing a user or service account from the roles/Owner role. Monitoring these activities helps prevent unauthorized access, enforces least privilege principles, and improves security auditing and compliance.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.3.5", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for Audit Configuration Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for Audit Configuration Changes", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "Google Cloud Platform (GCP) services generate audit log entries in the Admin Activity and Data Access logs, providing visibility into who performed what action, where, and when within GCP projects. These logs capture key details such as the identity of the API caller, timestamp, source IP address, request parameters, and response data. Cloud audit logging records API calls made through the GCP Console, SDKs, command-line tools, and other GCP services, offering a comprehensive activity history for security monitoring and compliance.", + "AdditionalInformation": "Admin activity and data access logs play a critical role in security analysis, resource change tracking, and compliance auditing. Configuring metric filters and alerts for audit configuration changes ensures that audit logging remains in its recommended state, allowing organizations to detect and respond to unauthorized modifications while ensuring all project activities remain fully auditable at any time.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "1.3.6", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for Custom Role Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for Custom Role Changes", + "Section": "1. IAM", + "SubSection": "1.3 Privilege Escalation Prevention", + "AttributeDescription": "It is recommended to set up a metric filter and alarm to track changes to Identity and Access Management (IAM) roles, including their creation, deletion, and updates. Google Cloud IAM provides predefined roles for granular access control but also allows organizations to create custom roles to meet specific needs.", + "AdditionalInformation": "IAM role modifications can impact security by granting excessive privileges if not properly managed. Monitoring role creation, deletion, and updates helps detect potential misconfigurations or over-privileged roles early, ensuring that only intended access permissions are assigned within the organization.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.1.1", + "Description": "Ensure That the Default Network Does Not Exist in a Project ", + "Checks": [ + "compute_network_default_in_use" + ], + "Attributes": [ + { + "Title": "Default Network Does Not Exist in a Project ", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "A project should not have a default network to prevent the use of preconfigured and potentially insecure network settings.", + "AdditionalInformation": "The default network automatically creates permissive firewall rules, including unrestricted internal traffic, SSH, RDP, and ICMP access, which increases the risk of unauthorized access. Additionally, it is an auto mode network, limiting flexibility in subnet configuration and restricting the use of Cloud VPN or VPC Network Peering. Organizations should create a custom network tailored to their security and networking needs and remove the default network to minimize exposure.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.1.2", + "Description": "Ensure Legacy Networks Do Not Exist for Older Projects", + "Checks": [ + "compute_network_not_legacy" + ], + "Attributes": [ + { + "Title": "Legacy Networks Do Not Exist for Older Projects", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "Projects should not have a legacy network configured to prevent the use of outdated and inflexible networking models. While new projects can no longer create legacy networks, older projects should be checked to ensure they are not still using them.", + "AdditionalInformation": "Legacy networks use a single global IPv4 prefix and a single gateway IP for the entire network, lacking subnetting capabilities. This design limits flexibility, prevents migration to auto or custom subnet networks, and can create performance bottlenecks or single points of failure for high-traffic workloads. Removing legacy networks and transitioning to modern networking models improves scalability, security, and resilience.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.1.4", + "Description": "Ensure That SSH Access Is Restricted From the Internet", + "Checks": [ + "compute_firewall_ssh_access_from_the_internet_allowed" + ], + "Attributes": [ + { + "Title": "SSH Access Is Restricted From the Internet", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "GCP Firewall Rules control ingress and egress traffic within a VPC Network. These rules define traffic conditions such as ports, protocols, and source/destination IPs. Firewall rules operate at the VPC level and cannot be shared across networks. Only IPv4 addresses are supported, and it is crucial to restrict generic (0.0.0.0/0) incoming traffic, particularly for SSH on Port 22, to prevent unauthorized access.", + "AdditionalInformation": "Firewall rules regulate traffic flow between instances and external networks. Allowing unrestricted inbound SSH access (0.0.0.0/0 on port 22) increases security risks by exposing instances to unauthorized access and brute-force attacks. To minimize threats, internet-facing access should be limited by specifying granular IP ranges and enforcing least privilege access.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.1.5", + "Description": "Ensure That RDP Access Is Restricted From the Internet", + "Checks": [ + "compute_firewall_rdp_access_from_the_internet_allowed" + ], + "Attributes": [ + { + "Title": "RDP Access Is Restricted From the Internet", + "Section": "2. Attack Surface", + "SubSection": "2.1 Network", + "AttributeDescription": "GCP Firewall Rules control incoming (ingress) and outgoing (egress) traffic within a VPC Network. Each rule specifies traffic conditions, including ports, protocols, and source/destination IPs. These rules operate at the VPC level, cannot be shared across networks, and support only IPv4 addresses. To enhance security, unrestricted RDP access (0.0.0.0/0 on port 3389) should be avoided to prevent unauthorized remote connections.", + "AdditionalInformation": "Firewall rules regulate traffic flow between instances and external networks. Allowing unrestricted RDP access from the Internet exposes virtual machines (VMs) to unauthorized access and brute-force attacks. To mitigate risks, internet-facing access should be restricted by enforcing least privilege access, defining specific IP ranges, and implementing secure remote access solutions such as Bastion hosts or VPNs.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.1", + "Description": "Ensure That Cloud Storage Bucket Is Not Anonymously or Publicly Accessible", + "Checks": [ + "cloudstorage_bucket_public_access" + ], + "Attributes": [ + { + "Title": "Cloud Storage Bucket Is Not Anonymously or Publicly Accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "IAM policies on Cloud Storage buckets should not allow anonymous or public access to prevent unauthorized data exposure.", + "AdditionalInformation": "Granting public or anonymous access allows anyone to access the buckets contents, posing a security risk, especially if sensitive data is stored. Restricting access ensures that only authorized users can interact with the bucket, reducing the risk of data breaches.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.2", + "Description": "Ensure 'user Connections' Database Flag for Cloud Sql Sql Server Instance Is Set to a Non-limiting Value", + "Checks": [ + "cloudsql_instance_sqlserver_user_connections_flag" + ], + "Attributes": [ + { + "Title": "user Connections Database Flag for Cloud Sql Sql Server Instance Is Set to a Non-limiting Value", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Verify the user connection limits for Cloud SQL SQL Server instances to ensure they are not unnecessarily restricting the number of simultaneous connections.", + "AdditionalInformation": "The user connections setting controls the maximum number of concurrent user connections allowed on an SQL Server instance. By default, SQL Server dynamically adjusts the number of connections as needed, up to a maximum of 32,767. Setting an artificial limit may prevent new connections from being established, leading to potential data loss or service outages. It is recommended to review and adjust this setting as necessary to avoid disruptions.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "2.2.3", + "Description": "Ensure 'remote access' database flag for Cloud SQL SQL Server instance is set to 'off'", + "Checks": [ + "cloudsql_instance_sqlserver_remote_access_flag" + ], + "Attributes": [ + { + "Title": "remote access database flag for Cloud SQL SQL Server instance is set to off", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Disable the remote access database flag for Cloud SQL SQL Server instances to prevent execution of stored procedures from remote servers.", + "AdditionalInformation": "The remote access option allows stored procedures to be executed from or on remote SQL Server instances. By default, this setting is enabled, which could be exploited for unauthorized query execution or Denial-of-Service (DoS) attacks by offloading processing to a target server. Disabling remote access enhances security by restricting stored procedure execution to the local server, reducing potential attack vectors. This recommendation applies to SQL Server database instances.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "2.2.5", + "Description": "Ensure That Cloud SQL Database Instances Do Not Implicitly Whitelist All Public IP Addresses", + "Checks": [ + "cloudsql_instance_public_access" + ], + "Attributes": [ + { + "Title": "Cloud SQL Database Instances Do Not Implicitly Whitelist All Public IP Addresses", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Restrict database server access to only trusted networks and IP addresses, preventing connections from public IPs.", + "AdditionalInformation": "Allowing unrestricted access to a database server increases the risk of unauthorized access and attacks. To minimize the attack surface, only trusted and necessary IP addresses should be whitelisted. Authorized networks should not be set to 0.0.0.0/0, which permits connections from anywhere. This control applies specifically to instances with public IP addresses.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.2.6", + "Description": "Ensure That Cloud SQL Database Instances Do Not Have Public IPs", + "Checks": [ + "cloudsql_instance_public_access" + ], + "Attributes": [ + { + "Title": "Cloud SQL Database Instances Do Not Have Public IPs", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Configure Second Generation Cloud SQL instances to use private IPs instead of public IPs.", + "AdditionalInformation": "Using private IPs for Cloud SQL databases enhances security by reducing exposure to external threats. It also improves network performance and lowers latency by keeping traffic within the internal network, minimizing the attack surface of the database.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "2.2.7", + "Description": "Ensure That BigQuery Datasets Are Not Anonymously or Publicly Accessible", + "Checks": [ + "bigquery_dataset_public_access" + ], + "Attributes": [ + { + "Title": "BigQuery Datasets Are Not Anonymously or Publicly Accessible", + "Section": "2. Attack Surface", + "SubSection": "2.2 Storage", + "AttributeDescription": "Ensure that IAM policies on BigQuery datasets do not allow anonymous or public access.", + "AdditionalInformation": "Granting access to allUsers or allAuthenticatedUsers permits unrestricted access to the dataset, which can lead to unauthorized data exposure. To protect sensitive information, public or anonymous access should be strictly prohibited.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.3", + "Description": "Ensure That Instances Are Not Configured To Use the Default Service Account With Full Access to All Cloud APIs", + "Checks": [ + "compute_instance_default_service_account_in_use_with_full_api_access" + ], + "Attributes": [ + { + "Title": "Instances Are Not Configured To Use the Default Service Account With Full Access to All Cloud APIs", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "To enforce the principle of least privilege and prevent potential privilege escalation, instances should not be assigned the Compute Engine default service account with the scope Allow full access to all Cloud APIs.", + "AdditionalInformation": "Google Compute Engine provides a default service account for instances to access necessary cloud services. This default service account has the Project Editor role, granting broad permissions over most cloud services except billing. When assigned to an instance, it can operate in three modes: 1.Allow default access Grants minimal required permissions (recommended). 2.Allow full access to all Cloud APIs Grants excessive access to all cloud services (not recommended). 3.Set access for each API Allows administrators to specify required APIs (preferred for least privilege). Assigning an instance the Compute Engine default service account with full access to all APIs can expose cloud operations to unauthorized users based on IAM roles. To reduce security risks, instances should use custom service accounts with minimal required permissions.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.3.4", + "Description": "Ensure Block Project-Wide SSH Keys Is Enabled for VM Instances ", + "Checks": [ + "compute_instance_block_project_wide_ssh_keys_disabled" + ], + "Attributes": [ + { + "Title": "Block Project-Wide SSH Keys Is Enabled for VM Instances ", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Instances should use instance-specific SSH keys instead of project-wide SSH keys to enhance security and reduce the risk of unauthorized access.", + "AdditionalInformation": "Project-wide SSH keys are stored in Compute Project metadata and can be used to access all instances within a project. While this simplifies SSH key management, it also increases security risksif a project-wide SSH key is compromised, all instances in the project could be affected. Using instance-specific SSH keys provides better security by limiting access to individual instances, reducing the attack surface in case of key compromise.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.5", + "Description": "Ensure Enable Connecting to Serial Ports Is Not Enabled for VM Instance", + "Checks": [ + "compute_instance_serial_ports_in_use" + ], + "Attributes": [ + { + "Title": "Enable Connecting to Serial Ports Is Not Enabled for VM Instance", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "The interactive serial console allows direct access to a virtual machines serial ports, similar to using a terminal window. When enabled, it allows connections from any IP address, creating a potential security risk. It is recommended to disable interactive serial console support.", + "AdditionalInformation": "A virtual machine instance has four virtual serial ports, often used by the operating system, BIOS, or other system-level entities for input and output. The first serial port (serial port 1) is commonly referred to as the serial console. Unlike SSH, the interactive serial console does not support IP-based access restrictions, meaning anyone with the correct SSH key, username, project ID, zone, and instance name could gain access. This exposes the instance to unauthorized access. To mitigate this risk, interactive serial console support should be disabled unless absolutely necessary.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "2.3.6", + "Description": "Ensure That IP Forwarding Is Not Enabled on Instances", + "Checks": [ + "compute_instance_ip_forwarding_is_enabled" + ], + "Attributes": [ + { + "Title": "IP Forwarding Is Not Enabled on Instances", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Google Compute Engine instances should not forward data packets unless explicitly required for routing purposes. By default, an instance cannot forward packets unless the source IP matches the instances IP address. Similarly, GCP wont deliver packets if the destination IP does not match the instance. To prevent unauthorized data forwarding, it is recommended to disable IP forwarding.", + "AdditionalInformation": "When IP forwarding is enabled (canIpForward field), an instance can send and receive packets with non-matching source or destination IPs, effectively allowing it to act as a network router. This can lead to data loss, information disclosure, or unauthorized traffic routing. To maintain security and prevent misuse, IP forwarding should be disabled unless explicitly required for network routing configurations.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "2.3.7", + "Description": "Ensure Compute Instances Are Launched With Shielded VM Enabled", + "Checks": [ + "compute_instance_shielded_vm_enabled" + ], + "Attributes": [ + { + "Title": "Compute Instances Are Launched With Shielded VM Enabled", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Shielded VMs are hardened virtual machines on Google Cloud Platform (GCP) designed to protect against rootkits, bootkits, and other low-level attacks. They ensure verifiable integrity using Secure Boot, virtual Trusted Platform Module (vTPM)-enabled Measured Boot, and integrity monitoring.", + "AdditionalInformation": "Shielded VMs use signed and verified firmware from Googles Certificate Authority to establish a root of trust. Secure Boot ensures only authentic software runs by verifying digital signatures, preventing unauthorized modifications. Integrity monitoring helps detect unexpected changes in the VMs boot process, while vTPM-enabled Measured Boot provides a baseline to compare against future boots. Enabling Shielded VMs enhances security by protecting against malware, unauthorized firmware changes, and persistent threats.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "2.3.8", + "Description": "Ensure That Compute Instances Do Not Have Public IP Addresses", + "Checks": [ + "compute_instance_public_ip" + ], + "Attributes": [ + { + "Title": "That Compute Instances Do Not Have Public IP Addresses", + "Section": "2. Attack Surface", + "SubSection": "2.3 Application", + "AttributeDescription": "Compute instances should not be assigned external IP addresses to minimize exposure to the internet and reduce security risks.", + "AdditionalInformation": "Public IP addresses increase the attack surface of Compute instances, making them more vulnerable to threats. Instead, instances should be placed behind load balancers or use private networking to control access and reduce the risk of unauthorized exposure.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "3.1.1", + "Description": "Ensure That Sinks Are Configured for All Log Entries", + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ], + "Attributes": [ + { + "Title": "Sinks Are Configured for All Log Entries", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to create a log sink to export and store copies of all log entries. This enables log aggregation across multiple projects and allows integration with a Security Information and Event Management (SIEM) system for centralized monitoring.", + "AdditionalInformation": "Cloud Logging retains logs for a limited period. To ensure long-term storage and better security analysis, logs should be exported to a destination such as Cloud Storage, BigQuery, or Cloud Pub/Sub. A log sink allows you to: Aggregate logs from multiple projects, folders, or billing accounts. Extend log retention beyond Cloud Loggings default retention period. Send logs to a SIEM system for real-time monitoring and threat detection. To ensure all logs are captured and exported: 1.Create a sink without filters to capture all log entries. 2.Choose an appropriate destination (e.g., Cloud Storage for long-term storage, BigQuery for analysis, or Pub/Sub for real-time processing). 3.Apply logging at the organization level to cover all associated projects. Implementing log sinks enhances security visibility, forensic capabilities, and compliance adherence across cloud environments.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.1.2", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for VPC Network Firewall Rule Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for VPC Network Firewall Rule Changes", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to configure a metric filter and alarm to monitor Virtual Private Cloud (VPC) Network Firewall rule changes. Tracking modifications to firewall rules helps ensure that unauthorized or unintended changes do not compromise network security.", + "AdditionalInformation": "Firewall rules control ingress and egress traffic within a VPC. Monitoring create or update events provides visibility into network access changes and helps quickly detect potential security threats or misconfigurations, reducing the risk of unauthorized access.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.3", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for VPC Network Route Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for VPC Network Route Changes", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to configure a metric filter and alarm to monitor Virtual Private Cloud (VPC) network route changes. Keeping track of modifications ensures that unauthorized or unintended changes do not disrupt expected network traffic flow.", + "AdditionalInformation": "GCP routes define how network traffic is directed between VM instances and external destinations. Monitoring route table changes helps ensure that traffic follows the intended path, preventing misconfigurations or malicious alterations that could lead to data exposure or connectivity issues.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.4", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for VPC Network Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for VPC Network Changes", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to configure a metric filter and alarm to monitor Virtual Private Cloud (VPC) network changes. This helps track modifications to VPC configurations and peer connections, ensuring that network traffic remains secure and follows the intended paths.", + "AdditionalInformation": "It is recommended to configure a metric filter and alarm to monitor Virtual Private Cloud (VPC) network changes. This helps track modifications to VPC configurations and peer connections, ensuring that network traffic remains secure and follows the intended paths.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.1.5", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for Cloud Storage IAM Permission Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for Cloud Storage IAM Permission Changes", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to set up a metric filter and alarm to monitor Cloud Storage Bucket IAM changes. This ensures that any modifications to bucket permissions are tracked and reviewed in a timely manner.", + "AdditionalInformation": "Monitoring changes to Cloud Storage IAM policies helps detect and correct unauthorized access or overly permissive configurations. This reduces the risk of data exposure or breaches by ensuring that sensitive storage buckets and their contents remain properly secured.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.6", + "Description": "Ensure That the Log Metric Filter and Alerts Exist for SQL Instance Configuration Changes", + "Checks": [ + "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled" + ], + "Attributes": [ + { + "Title": "Log Metric Filter and Alerts Exist for SQL Instance Configuration Changes", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "It is recommended to configure a metric filter and alarm to track SQL instance configuration changes. This helps in detecting and addressing misconfigurations that may impact security, availability, and compliance.", + "AdditionalInformation": "Monitoring SQL instance configuration changes ensures that critical security settings remain properly configured. Misconfigurations, such as disabling auto backups, allowing untrusted networks, or modifying high availability settings, can lead to data loss, security vulnerabilities, or operational disruptions. Early detection of such changes helps maintain a secure and resilient SQL environment.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.7", + "Description": "Ensure Logging is enabled for HTTP(S) Load Balancer ", + "Checks": [ + "compute_loadbalancer_logging_enabled" + ], + "Attributes": [ + { + "Title": "Logging is enabled for HTTP(S) Load Balancer ", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Enabling logging on an HTTPS Load Balancer captures all network traffic and its destination, providing visibility into requests made to your web applications.", + "AdditionalInformation": "Logging HTTPS network traffic helps monitor access patterns, troubleshoot issues, and enhance security by detecting suspicious activity or unauthorized access attempts.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.8", + "Description": "Ensure that VPC Flow Logs is Enabled for Every Subnet in a VPC Network", + "Checks": [ + "compute_subnet_flow_logs_enabled" + ], + "Attributes": [ + { + "Title": "VPC Flow Logs is Enabled for Every Subnet in a VPC Network", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Flow Logs capture and record IP traffic to and from network interfaces within VPC subnets. These logs are stored in Stackdriver Logging, allowing users to analyze traffic patterns, detect anomalies, and optimize network performance. It is recommended to enable Flow Logs for all critical VPC subnets to enhance network visibility and security.", + "AdditionalInformation": "VPC Flow Logs provide detailed insights into inbound and outbound traffic for virtual machines (VMs), whether they communicate with other VMs, on-premises data centers, Google services, or external networks. Enabling Flow Logs supports: Network monitoring Traffic analysis and cost optimization Incident investigation and forensics Real-time security threat detection For effective monitoring, Flow Logs should be configured to capture all traffic, use granular logging intervals, avoid log filtering, and include metadata for detailed investigations. Note that subnets reserved for internal HTTP(S) load balancing do not support Flow Logs.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.9", + "Description": "Ensure That the Log_connections Database Flag for Cloud SQL PostgreSQL Instance Is Set to On", + "Checks": [ + "cloudsql_instance_postgres_log_connections_flag" + ], + "Attributes": [ + { + "Title": "Log_connections Database Flag for Cloud SQL PostgreSQL Instance Is Set to On", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_connections setting should be enabled to log all attempted connections to the PostgreSQL server, including successful client authentication.", + "AdditionalInformation": "By default, PostgreSQL does not log connection attempts, making it harder to detect unauthorized access. Enabling log_connections provides visibility into all connection attempts, aiding in troubleshooting and identifying unusual or suspicious access patterns. This is particularly useful for security monitoring and incident response.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.10", + "Description": "Ensure That the Log_disconnections Database Flag for Cloud SQL PostgreSQL Instance Is Set to On", + "Checks": [ + "cloudsql_instance_postgres_log_disconnections_flag" + ], + "Attributes": [ + { + "Title": "Log_disconnections Database Flag for Cloud SQL PostgreSQL Instance Is Set to On", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_disconnections setting should be enabled to log the end of each PostgreSQL session, including session duration.", + "AdditionalInformation": "By default, PostgreSQL does not log session termination details, making it difficult to track session activity. Enabling log_disconnections helps monitor session durations and detect unusual activity. Combined with log_connections, it provides a complete audit trail of user access, aiding in troubleshooting and security monitoring.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.1.11", + "Description": "Ensure Log_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set Appropriately", + "Checks": [ + "cloudsql_instance_postgres_log_statement_flag" + ], + "Attributes": [ + { + "Title": "Log_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set Appropriately", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_statement setting in PostgreSQL determines which SQL statements are logged. Acceptable values include none, ddl, mod, and all. A recommended setting is ddl, which logs all data definition statements unless otherwise specified by the organizations logging policy.", + "AdditionalInformation": "Proper SQL statement logging is crucial for auditing and forensic analysis. If too many statements are logged, it can become difficult to extract relevant information; if too few are logged, critical details may be missing. Setting log_statement to an appropriate value, such as ddl, ensures a balance between comprehensive auditing and log manageability, aiding in database security and compliance.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.12", + "Description": "Ensure that the Log_min_messages Flag for a Cloud SQL PostgreSQL Instance is set at minimum to 'Warning'", + "Checks": [ + "cloudsql_instance_postgres_log_min_messages_flag" + ], + "Attributes": [ + { + "Title": "Log_min_messages Flag for a Cloud SQL PostgreSQL Instance is set at minimum to Warning", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_min_messages setting in PostgreSQL defines the minimum severity level for messages to be logged as errors. Accepted values range from DEBUG5 (least severe) to PANIC (most severe). Best practice is to set this value to ERROR, ensuring that only critical issues are logged unless an organizations policy requires a different threshold.", + "AdditionalInformation": "Proper logging is essential for troubleshooting and forensic analysis. If log_min_messages is not configured correctly, important error messages may be missed or unnecessary logs may clutter records. Setting this parameter to ERROR helps maintain a balance between capturing relevant issues and avoiding excessive log noise, improving system monitoring and security.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.1.13", + "Description": "Ensure Log_min_error_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set to Error or Stricter", + "Checks": [ + "cloudsql_instance_postgres_log_min_error_statement_flag" + ], + "Attributes": [ + { + "Title": "Log_min_error_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set to Error or Stricter", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_min_error_statement setting in PostgreSQL defines the minimum severity level for statements to be logged as errors. Valid values range from DEBUG5 (least severe) to PANIC (most severe). It is recommended to set this value to ERROR or stricter to ensure only relevant error statements are logged.", + "AdditionalInformation": "Proper logging aids in troubleshooting and forensic analysis. If log_min_error_statement is set too leniently, excessive log entries may make it difficult to identify actual errors. Conversely, if it is set too strictly, important errors may be missed. Setting this parameter to ERROR or higher ensures that significant issues are recorded while avoiding unnecessary log clutter.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.14", + "Description": "Ensure That the Log_min_duration_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set to '-1' (Disabled) ", + "Checks": [ + "cloudsql_instance_postgres_log_min_duration_statement_flag" + ], + "Attributes": [ + { + "Title": "Log_min_duration_statement Database Flag for Cloud SQL PostgreSQL Instance Is Set to -1 (Disabled) ", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "The log_min_duration_statement setting in PostgreSQL determines the minimum execution time (in milliseconds) required for a statement to be logged. It is recommended to disable this setting by setting its value to -1.", + "AdditionalInformation": "Logging SQL statements may expose sensitive information, which could lead to security risks if recorded in logs. Disabling this setting ensures that confidential data is not inadvertently captured. This recommendation applies to PostgreSQL database instances.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "3.1.15", + "Description": "Ensure That 'cloudsql.enable_pgaudit' Database Flag for each Cloud Sql Postgresql Instance Is Set to 'on' For Centralized Logging", + "Checks": [ + "cloudsql_instance_postgres_enable_pgaudit_flag" + ], + "Attributes": [ + { + "Title": "cloudsql.enable_pgaudit Database Flag for each Cloud Sql Postgresql Instance Is Set to on For Centralized Logging", + "Section": "3. Logging and Monitoring", + "SubSection": "3.1 Logging", + "AttributeDescription": "Ensure that the cloudsql.enable_pgaudit database flag is set to on for Cloud SQL PostgreSQL instances to enable centralized logging and auditing.", + "AdditionalInformation": "Enabling the pgaudit extension provides detailed session and object-level logging, which helps organizations comply with security standards such as government, financial, and ISO regulations. This logging capability enhances threat detection by monitoring security events on the database instance. Additionally, enabling this flag allows logs to be sent to Google Logs Explorer for centralized access and monitoring. This recommendation applies specifically to PostgreSQL database instances.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure That Retention Policies on Cloud Storage Buckets Used for Exporting Logs Are Configured Using Bucket Lock", + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ], + "Attributes": [ + { + "Title": "Retention Policies on Cloud Storage Buckets Used for Exporting Logs Are Configured Using Bucket Lock ", + "Section": "3. Logging and Monitoring", + "SubSection": "3.2 Retention", + "AttributeDescription": "Enabling retention policies on log storage buckets prevents logs from being overwritten or accidentally deleted. It is recommended to configure retention policies and enable Bucket Lock for all storage buckets used as log sinks.", + "AdditionalInformation": "Cloud Logging allows logs to be exported to storage buckets through sinks. Without a retention policy, logs can be altered or deleted, making it difficult to perform security investigations or comply with audit requirements. To ensure logs remain intact for forensics and security analysis: 1.Set a retention policy on log storage buckets to prevent early deletion. 2.Enable Bucket Lock to make the policy immutable, ensuring logs cannot be altered even by privileged users. 3.Apply appropriate access controls to protect logs from unauthorized access. By implementing retention policies and Bucket Lock, organizations preserve critical security logs, prevent attackers from covering their tracks, and enhance compliance with security regulations.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "3.3.1", + "Description": "Ensure Cloud Asset Inventory Is Enabled", + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ], + "Attributes": [ + { + "Title": "Cloud Asset Inventory Enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "Google Cloud Asset Inventory provides a historical view of GCP resources and IAM policies using a time-series database. It captures metadata on cloud resources, policy configurations, and runtime data. Enabling Cloud Asset Inventory allows for efficient searching and exporting of asset data.", + "AdditionalInformation": "Cloud Asset Inventory enhances security analysis, resource change tracking, and compliance auditing by maintaining a detailed history of GCP resources and their configurations. Enabling it across all GCP projects ensures visibility into changes, helping organizations detect misconfigurations, track policy changes, and strengthen security posture.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "3.3.2", + "Description": "Ensure 'Access Approval' is 'Enabled'", + "Checks": [ + "iam_account_access_approval_enabled" + ], + "Attributes": [ + { + "Title": "Access Aproval Enabled", + "Section": "3. Logging and Monitoring", + "SubSection": "3.3 Monitoring", + "AttributeDescription": "GCP Access Approval allows organizations to require explicit approval before Google support personnel can access their projects. Administrators can assign security roles in IAM to specific users who can review and approve these requests. Notifications of access requests, including the requesting Google employees details, are sent via email or Pub/Sub messages, providing transparency and control.", + "AdditionalInformation": "Managing who accesses your organizations data is critical for information security. While Google support may require access for troubleshooting, Access Approval ensures that access is only granted when explicitly authorized. This feature adds an additional layer of security and logging, ensuring that only approved Google personnel can access sensitive information.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.1.1", + "Description": "Ensure That DNSSEC Is Enabled for Cloud DNS ", + "Checks": [ + "dns_dnssec_disabled" + ], + "Attributes": [ + { + "Title": "DNSSEC Is Enabled for Cloud DNS ", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Cloud DNS provides a scalable and reliable domain name system (DNS) service. Domain Name System Security Extensions (DNSSEC) enhance DNS security by protecting domains against DNS hijacking, man-in-the-middle attacks, and other threats.", + "AdditionalInformation": "DNSSEC cryptographically signs DNS records, ensuring the integrity and authenticity of DNS responses. Without DNSSEC, attackers can manipulate DNS lookups, redirecting users to malicious websites through DNS hijacking or spoofing attacks. Enabling DNSSEC helps prevent unauthorized modifications to DNS records, reducing the risk of phishing, malware distribution, and other cyber threats.", + "LevelOfRisk": 1 + } + ] + }, + { + "Id": "4.1.2", + "Description": "Ensure That the Cloud SQL Database Instance Requires All Incoming Connections To Use SSL", + "Checks": [ + "cloudsql_instance_ssl_connections" + ], + "Attributes": [ + { + "Title": "Cloud SQL Database Instance Requires All Incoming Connections To Use SSL", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "Require all incoming connections to SQL database instances to use SSL encryption.", + "AdditionalInformation": "Unencrypted SQL database connections are vulnerable to man-in-the-middle (MITM) attacks, which can expose sensitive data such as credentials, queries, and results. Enforcing SSL ensures secure communication by encrypting data in transit, protecting against interception and unauthorized access. This recommendation applies to PostgreSQL, MySQL (Generation 1 and 2), and SQL Server 2017 instances.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.1.3", + "Description": "Ensure That RSASHA1 Is Not Used for the Key-Signing Key in Cloud DNS DNSSEC", + "Checks": [ + "dns_rsasha1_in_use_to_key_sign_in_dnssec" + ], + "Attributes": [ + { + "Title": "RSASHA1 Is Not Used for the Key-Signing Key in Cloud DNS DNSSEC", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "DNSSEC (Domain Name System Security Extensions) relies on cryptographic algorithms to ensure the integrity and authenticity of DNS responses. It is important to use strong and recommended algorithms for key signing to maintain robust security. SHA-1 is deprecated and requires explicit approval from Google if used.", + "AdditionalInformation": "DNSSEC signing algorithms play a critical role in securing DNS transactions. Using weak or outdated algorithms can expose DNS infrastructure to spoofing, hijacking, and other attacks. Organizations should select recommended and secure algorithms when enabling DNSSEC to protect DNS records from unauthorized modifications. If adjustments to DNSSEC settings are required, DNSSEC must be disabled and re-enabled with the updated configurations.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.1.4", + "Description": "Ensure That RSASHA1 Is Not Used for the Zone-Signing Key in Cloud DNS DNSSEC", + "Checks": [ + "dns_rsasha1_in_use_to_zone_sign_in_dnssec" + ], + "Attributes": [ + { + "Title": "RSASHA1 Is Not Used for the Zone-Signing Key in Cloud DNS DNSSEC", + "Section": "4. Encryption", + "SubSection": "4.1 In-Transit", + "AttributeDescription": "DNSSEC (Domain Name System Security Extensions) enhances DNS security by using cryptographic algorithms for zone signing and transaction security. It is essential to use strong and recommended algorithms for key signing. SHA-1 has been deprecated and requires Googles explicit approval and a support contract if used.", + "AdditionalInformation": "Using weak or outdated cryptographic algorithms compromises DNS integrity and exposes systems to threats like spoofing and hijacking. Organizations should ensure that DNSSEC settings use strong, recommended algorithms. If DNSSEC is already enabled and changes are needed, it must be disabled and re-enabled with updated configurations to apply the changes effectively.", + "LevelOfRisk": 2 + } + ] + }, + { + "Id": "4.2.1", + "Description": "Ensure VM Disks for Critical VMs Are Encrypted With Customer-Supplied Encryption Keys (CSEK)", + "Checks": [ + "compute_instance_encryption_with_csek_enabled" + ], + "Attributes": [ + { + "Title": "VM Disks for Critical VMs Are Encrypted With Customer-Supplied Encryption Keys (CSEK)", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Customer-Supplied Encryption Keys (CSEK) is a feature available in Google Cloud Storage and Google Compute Engine, allowing users to supply their own encryption keys. When you provide your key, Google uses it to protect the Google-generated keys that are responsible for encrypting and decrypting your data. By default, Google Compute Engine encrypts all data at rest automatically, managing this encryption for you with no additional action required. However, if you wish to have full control over the encryption process, you can choose to supply your own encryption keys.", + "AdditionalInformation": "By default, Compute Engine automatically encrypts all data at rest, with the service managing the encryption without any further input required from you or your application. However, if you require complete control over encryption, you have the option to provide your own encryption keys to manage the encryption of instance disks.", + "LevelOfRisk": 5 + } + ] + }, + { + "Id": "4.2.2", + "Description": "Ensure that Dataproc Cluster is encrypted using Customer-Managed Encryption Key", + "Checks": [ + "dataproc_encrypted_with_cmks_disabled" + ], + "Attributes": [ + { + "Title": "Dataproc Cluster is encrypted using Customer-Managed Encryption Key", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "When using Dataproc, the data associated with clusters and jobs is stored on Persistent Disks (PDs) linked to the Compute Engine VMs in your cluster and in a Cloud Storage staging bucket. This data is encrypted using a Google-generated Data Encryption Key (DEK) and a Key Encryption Key (KEK). The Customer-Managed Encryption Keys (CMEK) feature allows you to create, use, and revoke the KEK, although Google still controls the DEK used to encrypt the data.", + "AdditionalInformation": "Dataproc cluster data is encrypted using Google-managed keys: the Data Encryption Key (DEK) and the Key Encryption Key (KEK). If you wish to have control over the encryption of your cluster data, you can use your own Customer-Managed Keys (CMKs). Cloud KMS Customer-Managed Keys can add an extra layer of security and are commonly used in environments with strict compliance and security requirements.", + "LevelOfRisk": 4 + } + ] + }, + { + "Id": "4.2.3", + "Description": "Ensure BigQuery datasets are encrypted with Customer-Managed Keys (CMKs).", + "Checks": [ + "bigquery_dataset_cmk_encryption" + ], + "Attributes": [ + { + "Title": "BigQuery datasets are encrypted with Customer-Managed Keys (CMKs).", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Ensure that BigQuery datasets are encrypted using Customer-Managed Keys (CMKs) to gain more granular control over the data encryption and decryption process.", + "AdditionalInformation": "For enhanced control over encryption, Customer-Managed Encryption Keys (CMEK) can be implemented as a key management solution for BigQuery datasets.", + "LevelOfRisk": 3 + } + ] + }, + { + "Id": "4.2.4", + "Description": "Ensure BigQuery tables are encrypted with Customer-Managed Keys (CMKs).", + "Checks": [ + "bigquery_table_cmk_encryption" + ], + "Attributes": [ + { + "Title": "BigQuery tables are encrypted with Customer-Managed Keys (CMKs).", + "Section": "4. Encryption", + "SubSection": "4.2 At-Rest", + "AttributeDescription": "Ensure that BigQuery tables are encrypted using Customer-Managed Keys (CMKs) for more granular control over the data encryption and decryption process.", + "AdditionalInformation": "For greater control over encryption, Customer-Managed Encryption Keys (CMEK) can be utilized as the key management solution for BigQuery tables.", + "LevelOfRisk": 3 + } + ] + } + ] +} diff --git a/prowler/lib/check/compliance_models.py b/prowler/lib/check/compliance_models.py index fff0d6c38e..92bfaec168 100644 --- a/prowler/lib/check/compliance_models.py +++ b/prowler/lib/check/compliance_models.py @@ -183,6 +183,18 @@ class KISA_ISMSP_Requirement_Attribute(BaseModel): NonComplianceCases: Optional[list[str]] +# Prowler ThreatScore Requirement Attribute +class Prowler_ThreatScore_Requirement_Attribute(BaseModel): + """Prowler ThreatScore Requirement Attribute""" + + Title: str + Section: str + SubSection: str + AttributeDescription: str + AdditionalInformation: str + LevelOfRisk: int + + # Base Compliance Model # TODO: move this to compliance folder class Compliance_Requirement(BaseModel): @@ -198,6 +210,7 @@ class Compliance_Requirement(BaseModel): ISO27001_2013_Requirement_Attribute, AWS_Well_Architected_Requirement_Attribute, KISA_ISMSP_Requirement_Attribute, + Prowler_ThreatScore_Requirement_Attribute, # Generic_Compliance_Requirement_Attribute must be the last one since it is the fallback for generic compliance framework Generic_Compliance_Requirement_Attribute, ] diff --git a/prowler/lib/outputs/compliance/compliance.py b/prowler/lib/outputs/compliance/compliance.py index b74eafa97f..e0c686dd84 100644 --- a/prowler/lib/outputs/compliance/compliance.py +++ b/prowler/lib/outputs/compliance/compliance.py @@ -11,6 +11,9 @@ from prowler.lib.outputs.compliance.kisa_ismsp.kisa_ismsp import get_kisa_ismsp_ from prowler.lib.outputs.compliance.mitre_attack.mitre_attack import ( get_mitre_attack_table, ) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore import ( + get_prowler_threatscore_table, +) def display_compliance_table( @@ -72,6 +75,15 @@ def display_compliance_table( output_directory, compliance_overview, ) + elif "threatscore_" in compliance_framework: + get_prowler_threatscore_table( + findings, + bulk_checks_metadata, + compliance_framework, + output_filename, + output_directory, + compliance_overview, + ) else: get_generic_compliance_table( findings, diff --git a/prowler/lib/outputs/compliance/prowler_threatscore/__init__.py b/prowler/lib/outputs/compliance/prowler_threatscore/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/lib/outputs/compliance/prowler_threatscore/models.py b/prowler/lib/outputs/compliance/prowler_threatscore/models.py new file mode 100644 index 0000000000..2b5f5ada66 --- /dev/null +++ b/prowler/lib/outputs/compliance/prowler_threatscore/models.py @@ -0,0 +1,81 @@ +from typing import Optional + +from pydantic import BaseModel + + +class ProwlerThreatScoreAWSModel(BaseModel): + """ + ProwlerThreatScoreAWSModel generates a finding's output in AWS Prowler ThreatScore Compliance format. + """ + + Provider: str + Description: str + AccountId: str + Region: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Attributes_Title: str + Requirements_Attributes_Section: str + Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_AttributeDescription: str + Requirements_Attributes_AdditionalInformation: str + Requirements_Attributes_LevelOfRisk: int + Status: str + StatusExtended: str + ResourceId: str + ResourceName: str + CheckId: str + Muted: bool + + +class ProwlerThreatScoreAzureModel(BaseModel): + """ + ProwlerThreatScoreAzureModel generates a finding's output in Azure Prowler ThreatScore Compliance format. + """ + + Provider: str + Description: str + SubscriptionId: str + Location: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Attributes_Title: str + Requirements_Attributes_Section: str + Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_AttributeDescription: str + Requirements_Attributes_AdditionalInformation: str + Requirements_Attributes_LevelOfRisk: int + Status: str + StatusExtended: str + ResourceId: str + ResourceName: str + CheckId: str + Muted: bool + + +class ProwlerThreatScoreGCPModel(BaseModel): + """ + ProwlerThreatScoreGCPModel generates a finding's output in GCP Prowler ThreatScore Compliance format. + """ + + Provider: str + Description: str + ProjectId: str + Location: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Attributes_Title: str + Requirements_Attributes_Section: str + Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_AttributeDescription: str + Requirements_Attributes_AdditionalInformation: str + Requirements_Attributes_LevelOfRisk: int + Status: str + StatusExtended: str + ResourceId: str + ResourceName: str + CheckId: str + Muted: bool diff --git a/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore.py b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore.py new file mode 100644 index 0000000000..e041e3e7f3 --- /dev/null +++ b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore.py @@ -0,0 +1,121 @@ +from colorama import Fore, Style +from tabulate import tabulate + +from prowler.config.config import orange_color + + +def get_prowler_threatscore_table( + findings: list, + bulk_checks_metadata: dict, + compliance_framework: str, + output_filename: str, + output_directory: str, + compliance_overview: bool, +): + pillar_table = { + "Provider": [], + "Pillar": [], + "Status": [], + "Score": [], + "Muted": [], + } + pass_count = [] + fail_count = [] + muted_count = [] + pillars = {} + score_per_pillar = {} + number_findings_per_pillar = {} + 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 == "ProwlerThreatScore": + for requirement in compliance.Requirements: + for attribute in requirement.Attributes: + pillar = attribute.Section + + if pillar not in score_per_pillar.keys(): + score_per_pillar[pillar] = 0 + number_findings_per_pillar[pillar] = 0 + if finding.status == "FAIL" and not finding.muted: + score_per_pillar[pillar] += attribute.LevelOfRisk + number_findings_per_pillar[pillar] += 1 + + if pillar not in pillars: + pillars[pillar] = {"FAIL": 0, "PASS": 0, "Muted": 0} + + if finding.muted: + if index not in muted_count: + muted_count.append(index) + pillars[pillar]["Muted"] += 1 + else: + if finding.status == "FAIL" and index not in fail_count: + fail_count.append(index) + pillars[pillar]["FAIL"] += 1 + elif finding.status == "PASS" and index not in pass_count: + pass_count.append(index) + pillars[pillar]["PASS"] += 1 + + pillars = dict(sorted(pillars.items())) + for pillar in pillars: + pillar_table["Provider"].append(compliance.Provider) + pillar_table["Pillar"].append(pillar) + if number_findings_per_pillar[pillar] == 0: + pillar_table["Score"].append( + f"{Style.BRIGHT}{Fore.GREEN}0{Style.RESET_ALL}" + ) + else: + pillar_table["Score"].append( + f"{Style.BRIGHT}{Fore.RED}{score_per_pillar[pillar] / number_findings_per_pillar[pillar]:.2f}/5{Style.RESET_ALL}" + ) + if pillars[pillar]["FAIL"] > 0: + pillar_table["Status"].append( + f"{Fore.RED}FAIL({pillars[pillar]['FAIL']}){Style.RESET_ALL}" + ) + else: + pillar_table["Status"].append( + f"{Fore.GREEN}PASS({pillars[pillar]['PASS']}){Style.RESET_ALL}" + ) + pillar_table["Muted"].append( + f"{orange_color}{pillars[pillar]['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(pillar_table["Pillar"]) > 0: + print( + f"\nFramework {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Results:" + ) + + print( + tabulate( + pillar_table, + tablefmt="rounded_grid", + headers="keys", + ) + ) + + print( + f"{Style.BRIGHT}\n=== Risk Score Guide ===\nScore ranges from 1 (lowest risk) to 5 (highest risk), indicating the severity of the potential impact.{Style.RESET_ALL}" + ) + print( + f"{Style.BRIGHT}(Only sections containing results appear, the score is calculated as the sum of the level of risk of the failed findings divided by the number of failed findings){Style.RESET_ALL}" + ) + 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/prowler_threatscore/prowler_threatscore_aws.py b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws.py new file mode 100644 index 0000000000..2d876b402f --- /dev/null +++ b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws.py @@ -0,0 +1,91 @@ +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreAWSModel, +) +from prowler.lib.outputs.finding import Finding + + +class ProwlerThreatScoreAWS(ComplianceOutput): + """ + This class represents the AWS Prowler ThreatScore compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into AWS Prowler ThreatScore compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into AWS Prowler ThreatScore compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreAWSModel( + Provider=finding.provider, + Description=compliance.Description, + AccountId=finding.account_uid, + Region=finding.region, + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreAWSModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + AccountId="", + Region="", + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure.py b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure.py new file mode 100644 index 0000000000..01786e2d08 --- /dev/null +++ b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure.py @@ -0,0 +1,91 @@ +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreAzureModel, +) +from prowler.lib.outputs.finding import Finding + + +class ProwlerThreatScoreAzure(ComplianceOutput): + """ + This class represents the Azure Prowler ThreatScore compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into Azure Prowler ThreatScore compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into Azure Prowler ThreatScore compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreAzureModel( + Provider=finding.provider, + Description=compliance.Description, + SubscriptionId=finding.account_uid, + Location=finding.region, + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreAzureModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + SubscriptionId="", + Location="", + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp.py b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp.py new file mode 100644 index 0000000000..9bf577255f --- /dev/null +++ b/prowler/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp.py @@ -0,0 +1,91 @@ +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreGCPModel, +) +from prowler.lib.outputs.finding import Finding + + +class ProwlerThreatScoreGCP(ComplianceOutput): + """ + This class represents the GCP Prowler ThreatScore compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into GCP Prowler ThreatScore compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into GCP Prowler ThreatScore compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreGCPModel( + Provider=finding.provider, + Description=compliance.Description, + ProjectId=finding.account_uid, + Location=finding.region, + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = ProwlerThreatScoreGCPModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + ProjectId="", + Location="", + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Title=attribute.Title, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_SubSection=attribute.SubSection, + Requirements_Attributes_AttributeDescription=attribute.AttributeDescription, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_LevelOfRisk=attribute.LevelOfRisk, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + ) + self._data.append(compliance_row) diff --git a/prowler_threatscore_aws b/prowler_threatscore_aws new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler_threatscore_azure b/prowler_threatscore_azure new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler_threatscore_gcp b/prowler_threatscore_gcp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/lib/outputs/compliance/fixtures.py b/tests/lib/outputs/compliance/fixtures.py index f20cf6de85..3c8b71e3cd 100644 --- a/tests/lib/outputs/compliance/fixtures.py +++ b/tests/lib/outputs/compliance/fixtures.py @@ -13,6 +13,7 @@ from prowler.lib.check.compliance_models import ( Mitre_Requirement_Attribute_AWS, Mitre_Requirement_Attribute_Azure, Mitre_Requirement_Attribute_GCP, + Prowler_ThreatScore_Requirement_Attribute, ) CIS_1_4_AWS_NAME = "cis_1.4_aws" @@ -803,3 +804,129 @@ KISA_ISMSP_AWS = Compliance( ), ], ) + +PROWLER_THREATSCORE_AWS_NAME = "prowler_threatscore_aws" +PROWLER_THREATSCORE_AWS = Compliance( + Framework="ProwlerThreatScore", + Version="1.0", + Provider="AWS", + Description="Prowler ThreatScore Compliance Framework for AWS ensures that the AWS account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + Requirements=[ + Compliance_Requirement( + Id="1.1.1", + Description="Ensure MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="MFA enabled for 'root'", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.", + LevelOfRisk=5, + ) + ], + Checks=[ + "iam_root_mfa_enabled", + ], + ), + Compliance_Requirement( + Id="1.1.2", + Description="Ensure hardware MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="CloudTrail logging enabled", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.", + LevelOfRisk=3, + ) + ], + Checks=[], + ), + ], +) + +PROWLER_THREATSCORE_AZURE_NAME = "prowler_threatscore_azure" +PROWLER_THREATSCORE_AZURE = Compliance( + Framework="ProwlerThreatScore", + Version="1.0", + Provider="Azure", + Description="Prowler ThreatScore Compliance Framework for Azure ensures that the Azure account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + Requirements=[ + Compliance_Requirement( + Id="1.1.1", + Description="Ensure MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="MFA enabled for 'root'", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.", + LevelOfRisk=5, + ) + ], + Checks=[ + "iam_root_mfa_enabled", + ], + ), + Compliance_Requirement( + Id="1.1.2", + Description="Ensure hardware MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="CloudTrail logging enabled", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.", + LevelOfRisk=3, + ) + ], + Checks=[], + ), + ], +) + +PROWLER_THREATSCORE_GCP_NAME = "prowler_threatscore_gcp" +PROWLER_THREATSCORE_GCP = Compliance( + Framework="ProwlerThreatScore", + Version="1.0", + Provider="GCP", + Description="Prowler ThreatScore Compliance Framework for GCP ensures that the GCP account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption", + Requirements=[ + Compliance_Requirement( + Id="1.1.1", + Description="Ensure MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="MFA enabled for 'root'", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.", + LevelOfRisk=5, + ) + ], + Checks=[ + "iam_root_mfa_enabled", + ], + ), + Compliance_Requirement( + Id="1.1.2", + Description="Ensure hardware MFA is enabled for the 'root' user account", + Attributes=[ + Prowler_ThreatScore_Requirement_Attribute( + Title="CloudTrail logging enabled", + Section="1. IAM", + SubSection="1.1 Authentication", + AttributeDescription="The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.", + AdditionalInformation="A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.", + LevelOfRisk=3, + ) + ], + Checks=[], + ), + ], +) diff --git a/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws_test.py b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws_test.py new file mode 100644 index 0000000000..28cf82ab44 --- /dev/null +++ b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_aws_test.py @@ -0,0 +1,140 @@ +from datetime import datetime +from io import StringIO + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreAWSModel, +) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_aws import ( + ProwlerThreatScoreAWS, +) +from tests.lib.outputs.compliance.fixtures import ( + PROWLER_THREATSCORE_AWS, + PROWLER_THREATSCORE_AWS_NAME, +) +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 TestProwlerThreatScoreAWS: + def test_output_transform(self): + findings = [ + generate_finding_output(compliance={"ProwlerThreatScore-1.0": "1.1.1"}) + ] + + output = ProwlerThreatScoreAWS( + findings, PROWLER_THREATSCORE_AWS, PROWLER_THREATSCORE_AWS_NAME + ) + output_data = output.data[0] + assert isinstance(output_data, ProwlerThreatScoreAWSModel) + assert output_data.Provider == "aws" + assert output_data.Description == PROWLER_THREATSCORE_AWS.Description + assert output_data.AccountId == AWS_ACCOUNT_NUMBER + assert output_data.Region == AWS_REGION_EU_WEST_1 + assert output_data.Requirements_Id == PROWLER_THREATSCORE_AWS.Requirements[0].Id + assert ( + output_data.Requirements_Description + == PROWLER_THREATSCORE_AWS.Requirements[0].Description + ) + assert ( + output_data.Requirements_Attributes_Title + == PROWLER_THREATSCORE_AWS.Requirements[0].Attributes[0].Title + ) + assert ( + output_data.Requirements_Attributes_Section + == PROWLER_THREATSCORE_AWS.Requirements[0].Attributes[0].Section + ) + assert ( + output_data.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_AWS.Requirements[0].Attributes[0].SubSection + ) + assert ( + output_data.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_AWS.Requirements[0] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_AWS.Requirements[0] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_AWS.Requirements[0].Attributes[0].LevelOfRisk + ) + assert output_data.Status == "PASS" + assert output_data.StatusExtended == "" + assert output_data.ResourceId == "" + assert output_data.ResourceName == "" + assert output_data.CheckId == "test-check-id" + assert not output_data.Muted + # Test manual check + output_data_manual = output.data[1] + assert output_data_manual.Provider == "aws" + assert output_data_manual.AccountId == "" + assert output_data_manual.Region == "" + assert ( + output_data_manual.Requirements_Id + == PROWLER_THREATSCORE_AWS.Requirements[1].Id + ) + assert ( + output_data_manual.Requirements_Description + == PROWLER_THREATSCORE_AWS.Requirements[1].Description + ) + assert ( + output_data_manual.Requirements_Attributes_Title + == PROWLER_THREATSCORE_AWS.Requirements[1].Attributes[0].Title + ) + assert ( + output_data_manual.Requirements_Attributes_Section + == PROWLER_THREATSCORE_AWS.Requirements[1].Attributes[0].Section + ) + assert ( + output_data_manual.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_AWS.Requirements[1].Attributes[0].SubSection + ) + assert ( + output_data_manual.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_AWS.Requirements[1] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data_manual.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_AWS.Requirements[1] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data_manual.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_AWS.Requirements[1].Attributes[0].LevelOfRisk + ) + assert output_data_manual.Status == "MANUAL" + assert output_data_manual.StatusExtended == "Manual check" + assert output_data_manual.ResourceId == "manual_check" + assert output_data_manual.ResourceName == "Manual check" + assert output_data_manual.CheckId == "manual" + assert not output_data_manual.Muted + + @freeze_time(datetime.now()) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output(compliance={"ProwlerThreatScore-1.0": "1.1.1"}) + ] + output = ProwlerThreatScoreAWS( + findings, PROWLER_THREATSCORE_AWS, PROWLER_THREATSCORE_AWS_NAME + ) + 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() + expected_csv = f"PROVIDER;DESCRIPTION;ACCOUNTID;REGION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_TITLE;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_SUBSECTION;REQUIREMENTS_ATTRIBUTES_ATTRIBUTEDESCRIPTION;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_LEVELOFRISK;STATUS;STATUSEXTENDED;RESOURCEID;RESOURCENAME;CHECKID;MUTED\r\naws;Prowler ThreatScore Compliance Framework for AWS ensures that the AWS account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;123456789012;eu-west-1;{datetime.now()};1.1.1;Ensure MFA is enabled for the 'root' user account;MFA enabled for 'root';1. IAM;1.1 Authentication;The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.;5;PASS;;;;test-check-id;False\r\naws;Prowler ThreatScore Compliance Framework for AWS ensures that the AWS account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;;;{datetime.now()};1.1.2;Ensure hardware MFA is enabled for the 'root' user account;CloudTrail logging enabled;1. IAM;1.1 Authentication;The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.;3;MANUAL;Manual check;manual_check;Manual check;manual;False\r\n" + assert content == expected_csv diff --git a/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure_test.py b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure_test.py new file mode 100644 index 0000000000..0dec129f06 --- /dev/null +++ b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_azure_test.py @@ -0,0 +1,150 @@ +from datetime import datetime +from io import StringIO + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreAzureModel, +) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_azure import ( + ProwlerThreatScoreAzure, +) +from tests.lib.outputs.compliance.fixtures import ( + PROWLER_THREATSCORE_AZURE, + PROWLER_THREATSCORE_AZURE_NAME, +) +from tests.lib.outputs.fixtures.fixtures import generate_finding_output +from tests.providers.azure.azure_fixtures import ( + AZURE_SUBSCRIPTION_ID, + AZURE_SUBSCRIPTION_NAME, +) + + +class TestProwlerThreatScoreAzure: + def test_output_transform(self): + findings = [ + generate_finding_output( + compliance={"ProwlerThreatScore-1.0": "1.1.1"}, + provider="azure", + account_name=AZURE_SUBSCRIPTION_NAME, + account_uid=AZURE_SUBSCRIPTION_ID, + region="", + ) + ] + + output = ProwlerThreatScoreAzure( + findings, PROWLER_THREATSCORE_AZURE, PROWLER_THREATSCORE_AZURE_NAME + ) + output_data = output.data[0] + assert isinstance(output_data, ProwlerThreatScoreAzureModel) + assert output_data.Provider == "azure" + assert output_data.Description == PROWLER_THREATSCORE_AZURE.Description + assert output_data.SubscriptionId == AZURE_SUBSCRIPTION_ID + assert output_data.Location == "" + assert ( + output_data.Requirements_Id == PROWLER_THREATSCORE_AZURE.Requirements[0].Id + ) + assert ( + output_data.Requirements_Description + == PROWLER_THREATSCORE_AZURE.Requirements[0].Description + ) + assert ( + output_data.Requirements_Attributes_Title + == PROWLER_THREATSCORE_AZURE.Requirements[0].Attributes[0].Title + ) + assert ( + output_data.Requirements_Attributes_Section + == PROWLER_THREATSCORE_AZURE.Requirements[0].Attributes[0].Section + ) + assert ( + output_data.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_AZURE.Requirements[0].Attributes[0].SubSection + ) + assert ( + output_data.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_AZURE.Requirements[0] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_AZURE.Requirements[0] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_AZURE.Requirements[0].Attributes[0].LevelOfRisk + ) + assert output_data.Status == "PASS" + assert output_data.StatusExtended == "" + assert output_data.ResourceId == "" + assert output_data.ResourceName == "" + assert output_data.CheckId == "test-check-id" + assert not output_data.Muted + # Test manual check + output_data_manual = output.data[1] + assert output_data_manual.Provider == "azure" + assert output_data_manual.SubscriptionId == "" + assert output_data_manual.Location == "" + assert ( + output_data_manual.Requirements_Id + == PROWLER_THREATSCORE_AZURE.Requirements[1].Id + ) + assert ( + output_data_manual.Requirements_Description + == PROWLER_THREATSCORE_AZURE.Requirements[1].Description + ) + assert ( + output_data_manual.Requirements_Attributes_Title + == PROWLER_THREATSCORE_AZURE.Requirements[1].Attributes[0].Title + ) + assert ( + output_data_manual.Requirements_Attributes_Section + == PROWLER_THREATSCORE_AZURE.Requirements[1].Attributes[0].Section + ) + assert ( + output_data_manual.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_AZURE.Requirements[1].Attributes[0].SubSection + ) + assert ( + output_data_manual.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_AZURE.Requirements[1] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data_manual.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_AZURE.Requirements[1] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data_manual.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_AZURE.Requirements[1].Attributes[0].LevelOfRisk + ) + assert output_data_manual.Status == "MANUAL" + assert output_data_manual.StatusExtended == "Manual check" + assert output_data_manual.ResourceId == "manual_check" + assert output_data_manual.ResourceName == "Manual check" + assert output_data_manual.CheckId == "manual" + + @freeze_time(datetime.now()) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output(compliance={"ProwlerThreatScore-1.0": "1.1.1"}) + ] + output = ProwlerThreatScoreAzure( + findings, PROWLER_THREATSCORE_AZURE, PROWLER_THREATSCORE_AZURE_NAME + ) + 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() + expected_csv = f"PROVIDER;DESCRIPTION;SUBSCRIPTIONID;LOCATION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_TITLE;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_SUBSECTION;REQUIREMENTS_ATTRIBUTES_ATTRIBUTEDESCRIPTION;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_LEVELOFRISK;STATUS;STATUSEXTENDED;RESOURCEID;RESOURCENAME;CHECKID;MUTED\r\naws;Prowler ThreatScore Compliance Framework for Azure ensures that the Azure account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;123456789012;eu-west-1;{datetime.now()};1.1.1;Ensure MFA is enabled for the 'root' user account;MFA enabled for 'root';1. IAM;1.1 Authentication;The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.;5;PASS;;;;test-check-id;False\r\nazure;Prowler ThreatScore Compliance Framework for Azure ensures that the Azure account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;;;{datetime.now()};1.1.2;Ensure hardware MFA is enabled for the 'root' user account;CloudTrail logging enabled;1. IAM;1.1 Authentication;The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.;3;MANUAL;Manual check;manual_check;Manual check;manual;False\r\n" + assert content == expected_csv diff --git a/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp_test.py b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp_test.py new file mode 100644 index 0000000000..40a5e60494 --- /dev/null +++ b/tests/lib/outputs/compliance/prowler_threatscore/prowler_threatscore_gcp_test.py @@ -0,0 +1,147 @@ +from datetime import datetime +from io import StringIO + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.prowler_threatscore.models import ( + ProwlerThreatScoreGCPModel, +) +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_gcp import ( + ProwlerThreatScoreGCP, +) +from tests.lib.outputs.compliance.fixtures import ( + PROWLER_THREATSCORE_GCP, + PROWLER_THREATSCORE_GCP_NAME, +) +from tests.lib.outputs.fixtures.fixtures import generate_finding_output +from tests.providers.gcp.gcp_fixtures import GCP_PROJECT_ID + + +class TestProwlerThreatScoreGCP: + def test_output_transform(self): + findings = [ + generate_finding_output( + compliance={"ProwlerThreatScore-1.0": "1.1.1"}, + provider="gcp", + account_name=GCP_PROJECT_ID, + account_uid=GCP_PROJECT_ID, + region="", + ) + ] + + output = ProwlerThreatScoreGCP( + findings, PROWLER_THREATSCORE_GCP, PROWLER_THREATSCORE_GCP_NAME + ) + output_data = output.data[0] + assert isinstance(output_data, ProwlerThreatScoreGCPModel) + assert output_data.Provider == "gcp" + assert output_data.Description == PROWLER_THREATSCORE_GCP.Description + assert output_data.ProjectId == GCP_PROJECT_ID + assert output_data.Location == "" + assert output_data.Requirements_Id == PROWLER_THREATSCORE_GCP.Requirements[0].Id + assert ( + output_data.Requirements_Description + == PROWLER_THREATSCORE_GCP.Requirements[0].Description + ) + assert ( + output_data.Requirements_Attributes_Title + == PROWLER_THREATSCORE_GCP.Requirements[0].Attributes[0].Title + ) + assert ( + output_data.Requirements_Attributes_Section + == PROWLER_THREATSCORE_GCP.Requirements[0].Attributes[0].Section + ) + assert ( + output_data.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_GCP.Requirements[0].Attributes[0].SubSection + ) + assert ( + output_data.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_GCP.Requirements[0] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_GCP.Requirements[0] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_GCP.Requirements[0].Attributes[0].LevelOfRisk + ) + assert output_data.Status == "PASS" + assert output_data.StatusExtended == "" + assert output_data.ResourceId == "" + assert output_data.ResourceName == "" + assert output_data.CheckId == "test-check-id" + assert not output_data.Muted + # Test manual check + output_data_manual = output.data[1] + assert output_data_manual.Provider == "gcp" + assert output_data_manual.ProjectId == "" + assert output_data_manual.Location == "" + assert ( + output_data_manual.Requirements_Id + == PROWLER_THREATSCORE_GCP.Requirements[1].Id + ) + assert ( + output_data_manual.Requirements_Description + == PROWLER_THREATSCORE_GCP.Requirements[1].Description + ) + assert ( + output_data_manual.Requirements_Attributes_Title + == PROWLER_THREATSCORE_GCP.Requirements[1].Attributes[0].Title + ) + assert ( + output_data_manual.Requirements_Attributes_Section + == PROWLER_THREATSCORE_GCP.Requirements[1].Attributes[0].Section + ) + assert ( + output_data_manual.Requirements_Attributes_SubSection + == PROWLER_THREATSCORE_GCP.Requirements[1].Attributes[0].SubSection + ) + assert ( + output_data_manual.Requirements_Attributes_AttributeDescription + == PROWLER_THREATSCORE_GCP.Requirements[1] + .Attributes[0] + .AttributeDescription + ) + assert ( + output_data_manual.Requirements_Attributes_AdditionalInformation + == PROWLER_THREATSCORE_GCP.Requirements[1] + .Attributes[0] + .AdditionalInformation + ) + assert ( + output_data_manual.Requirements_Attributes_LevelOfRisk + == PROWLER_THREATSCORE_GCP.Requirements[1].Attributes[0].LevelOfRisk + ) + assert output_data_manual.Status == "MANUAL" + assert output_data_manual.StatusExtended == "Manual check" + assert output_data_manual.ResourceId == "manual_check" + assert output_data_manual.ResourceName == "Manual check" + assert output_data_manual.CheckId == "manual" + assert not output_data_manual.Muted + + @freeze_time(datetime.now()) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output(compliance={"ProwlerThreatScore-1.0": "1.1.1"}) + ] + output = ProwlerThreatScoreGCP( + findings, PROWLER_THREATSCORE_GCP, PROWLER_THREATSCORE_GCP_NAME + ) + 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() + expected_csv = f"PROVIDER;DESCRIPTION;PROJECTID;LOCATION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_TITLE;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_SUBSECTION;REQUIREMENTS_ATTRIBUTES_ATTRIBUTEDESCRIPTION;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_LEVELOFRISK;STATUS;STATUSEXTENDED;RESOURCEID;RESOURCENAME;CHECKID;MUTED\r\naws;Prowler ThreatScore Compliance Framework for GCP ensures that the GCP account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;123456789012;eu-west-1;{datetime.now()};1.1.1;Ensure MFA is enabled for the 'root' user account;MFA enabled for 'root';1. IAM;1.1 Authentication;The root user account holds the highest level of privileges within an AWS account. Enabling Multi-Factor Authentication (MFA) enhances security by adding an additional layer of protection beyond just a username and password. With MFA activated, users must provide their credentials (username and password) along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;Enabling MFA enhances console security by requiring the authenticating user to both possess a time-sensitive key-generating device and have knowledge of their credentials.;5;PASS;;;;test-check-id;False\r\ngcp;Prowler ThreatScore Compliance Framework for GCP ensures that the GCP account is compliant taking into account four main pillars: Identity and Access Management, Attack Surface, Forensic Readiness and Encryption;;;{datetime.now()};1.1.2;Ensure hardware MFA is enabled for the 'root' user account;CloudTrail logging enabled;1. IAM;1.1 Authentication;The root user account in AWS has the highest level of privileges. Multi-Factor Authentication (MFA) enhances security by adding an extra layer of protection beyond a username and password. When MFA is enabled, users must enter their credentials along with a unique authentication code generated by their AWS MFA device when signing into an AWS website.;A hardware MFA has a smaller attack surface compared to a virtual MFA. Unlike a virtual MFA, which relies on a mobile device that may be vulnerable to malware or compromise, a hardware MFA operates independently, reducing exposure to potential security threats.;3;MANUAL;Manual check;manual_check;Manual check;manual;False\r\n" + + assert content == expected_csv diff --git a/util/generate_compliance_json_from_csv_threatscope.py b/util/generate_compliance_json_from_csv_threatscope.py new file mode 100644 index 0000000000..47865d0c8d --- /dev/null +++ b/util/generate_compliance_json_from_csv_threatscope.py @@ -0,0 +1,36 @@ +import csv +import json +import sys + +# Convert a CSV file following the ThreatScore CSV format into a Prowler Compliance JSON file +# CSV fields: +# Id, Title, Description, Section, SubSection, AttributeDescription, AdditionalInformation, LevelOfRisk, Checks + +# get the CSV filename to convert from +file_name = sys.argv[1] + +# read the CSV file rows and use the column fields to form the Prowler compliance JSON file 'prowler_threatscore_aws.json' +output = {"Framework": "ProwlerThreatScore", "Version": "1.0", "Requirements": []} +with open(file_name, newline="", encoding="utf-8") as f: + reader = csv.reader(f, delimiter=",") + for row in reader: + attribute = { + "Title": row[1], + "Section": row[3], + "SubSection": row[4], + "AttributeDescription": row[5], + "AdditionalInformation": row[6], + "LevelOfRisk": row[7], + } + output["Requirements"].append( + { + "Id": row[0], + "Description": row[2], + "Checks": list(map(str.strip, row[8].split(","))), + "Attributes": [attribute], + } + ) + +# Write the output Prowler compliance JSON file 'prowler_threatscore_aws.json' locally +with open("prowler_threatscore_azure.json", "w", encoding="utf-8") as outfile: + json.dump(output, outfile, indent=4, ensure_ascii=False) diff --git a/util/get_prowler_threatscore_from_generic_output.py b/util/get_prowler_threatscore_from_generic_output.py new file mode 100644 index 0000000000..d3cd53a6b6 --- /dev/null +++ b/util/get_prowler_threatscore_from_generic_output.py @@ -0,0 +1,52 @@ +import csv +import json +import sys + +file_name_output = sys.argv[1] # It is the output CSV file +file_name_compliance = sys.argv[2] # It is the compliance JSON file + + +number_of_findings_per_pillar = {} +score_per_pillar = {} +# Read the compliance JSON file +with open(file_name_compliance, "r") as file: + data = json.load(file) + +# Read the output CSV file +with open(file_name_output, "r") as file: + reader = csv.reader(file, delimiter=";") + headers = next(reader) + if "CHECK_ID" in headers: + check_id_index = headers.index("CHECK_ID") + if "STATUS" in headers: + status_index = headers.index("STATUS") + if "MUTED" in headers: + muted_index = headers.index("MUTED") + for row in reader: + for requirement in data["Requirements"]: + # Take the column that contains the CHECK_ID + if row[check_id_index] in requirement["Checks"]: + if ( + requirement["Attributes"][0]["Section"] + not in number_of_findings_per_pillar.keys() + ): + number_of_findings_per_pillar[ + requirement["Attributes"][0]["Section"] + ] = 0 + if ( + requirement["Attributes"][0]["Section"] + not in score_per_pillar.keys() + ): + score_per_pillar[requirement["Attributes"][0]["Section"]] = 0 + if row[status_index] == "FAIL" and row[muted_index] != "TRUE": + number_of_findings_per_pillar[ + requirement["Attributes"][0]["Section"] + ] += 1 + score_per_pillar[ + requirement["Attributes"][0]["Section"] + ] += requirement["Attributes"][0]["LevelOfRisk"] + +for key, value in number_of_findings_per_pillar.items(): + print("Pillar:", key) + print("Score:", score_per_pillar[key] / value) + print("--------------------------------") From 78439b4c0c262e0e09ab68e371e233020a413932 Mon Sep 17 00:00:00 2001 From: Erlend Ekern Date: Tue, 29 Apr 2025 09:15:47 +0200 Subject: [PATCH 228/359] chore(dockerfile): add image source as docker label (#7617) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 1c19358a3f..eb79e31cce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.12.10-alpine3.20 LABEL maintainer="https://github.com/prowler-cloud/prowler" +LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler" # Update system dependencies and install essential tools #hadolint ignore=DL3018 From 5a0fb13ece07371119cdad3eefb8722dc0d7f6e8 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Tue, 29 Apr 2025 13:01:12 +0545 Subject: [PATCH 229/359] fix(run-sh): Use poetry's env (#7621) --- .../aws/multi-account-securityhub/run-prowler-securityhub.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/aws/multi-account-securityhub/run-prowler-securityhub.sh b/contrib/aws/multi-account-securityhub/run-prowler-securityhub.sh index 51fef78f77..c101da8613 100755 --- a/contrib/aws/multi-account-securityhub/run-prowler-securityhub.sh +++ b/contrib/aws/multi-account-securityhub/run-prowler-securityhub.sh @@ -1,6 +1,9 @@ #!/bin/bash # Run Prowler against All AWS Accounts in an AWS Organization +# Activate Poetry Environment +eval "$(poetry env activate)" + # Show Prowler Version prowler -v From ceacd077d26b57f34cf9b82df245f5a77c0be0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Tue, 29 Apr 2025 09:39:24 +0200 Subject: [PATCH 230/359] fix(typos): remove unneeded files (#7627) --- prowler_threatscore_aws | 0 prowler_threatscore_azure | 0 prowler_threatscore_gcp | 0 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 prowler_threatscore_aws delete mode 100644 prowler_threatscore_azure delete mode 100644 prowler_threatscore_gcp diff --git a/prowler_threatscore_aws b/prowler_threatscore_aws deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/prowler_threatscore_azure b/prowler_threatscore_azure deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/prowler_threatscore_gcp b/prowler_threatscore_gcp deleted file mode 100644 index e69de29bb2..0000000000 From 82eecec27734a7a152fc15029c81377371edccbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 30 Apr 2025 11:43:41 +0200 Subject: [PATCH 231/359] feat(sharepoint): add new check related with OneDrive Sync (#7589) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- README.md | 2 +- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...restricted_unmanaged_devices.metadata.json | 30 ++++ ...drive_sync_restricted_unmanaged_devices.py | 48 +++++++ .../services/sharepoint/sharepoint_service.py | 4 +- ...harepoint_external_sharing_managed_test.py | 6 + ...epoint_external_sharing_restricted_test.py | 3 + ...harepoint_guest_sharing_restricted_test.py | 3 + ...int_modern_authentication_required_test.py | 3 + ..._sync_restricted_unmanaged_devices_test.py | 129 ++++++++++++++++++ .../sharepoint/sharepoint_service_test.py | 6 + 12 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/__init__.py create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.metadata.json create mode 100644 prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.py create mode 100644 tests/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices_test.py diff --git a/README.md b/README.md index addd596590..fa89204448 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | -| M365 | 5 | 2 | 1 | 0 | +| M365 | 44 | 2 | 1 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | > You can list the checks, services, compliance frameworks and categories with `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`. diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 51b7e45c7a..1c7cbc4175 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_presenters_restricted` [(#7613)](https://github.com/prowler-cloud/prowler/pull/7613) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) +- Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) ### Fixed diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/__init__.py b/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.metadata.json b/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.metadata.json new file mode 100644 index 0000000000..8f08f26c60 --- /dev/null +++ b/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "sharepoint_onedrive_sync_restricted_unmanaged_devices", + "CheckTitle": "Ensure OneDrive sync is restricted for unmanaged devices.", + "CheckType": [], + "ServiceName": "sharepoint", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Sharepoint Settings", + "Description": "Microsoft OneDrive allows users to sign in their cloud tenant account and begin syncing select folders or the entire contents of OneDrive to a local computer. By default, this includes any computer with OneDrive already installed, whether it is Entra Joined, Entra Hybrid Joined or Active Directory Domain joined. The recommended state for this setting is Allow syncing only on computers joined to specific domains Enabled: Specify the AD domain GUID(s).", + "Risk": "Unmanaged devices can pose a security risk by allowing users to sync sensitive data to unauthorized devices, potentially leading to data leakage or unauthorized access.", + "RelatedUrl": "https://learn.microsoft.com/en-us/graph/api/resources/sharepoint?view=graph-rest-1.0", + "Remediation": { + "Code": { + "CLI": "Set-SPOTenantSyncClientRestriction -Enable -DomainGuids '; ; ...'", + "NativeIaC": "", + "Other": "1. Navigate to SharePoint admin center https://admin.microsoft.com/sharepoint 2. Click Settings then select OneDrive - Sync. 3. Check the Allow syncing only on computers joined to specific domains. 4. Use the Get-ADDomain PowerShell command on the on-premises server to obtain the GUID for each on-premises domain. 5. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict OneDrive sync to managed devices to prevent unauthorized access to sensitive data.", + "Url": "https://learn.microsoft.com/en-us/sharepoint/allow-syncing-only-on-specific-domains" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.py b/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.py new file mode 100644 index 0000000000..ca6d5415fa --- /dev/null +++ b/prowler/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices.py @@ -0,0 +1,48 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.sharepoint.sharepoint_client import ( + sharepoint_client, +) + + +class sharepoint_onedrive_sync_restricted_unmanaged_devices(Check): + """ + Check if OneDrive sync is restricted for unmanaged devices. + + This check verifies that OneDrive sync is restricted to managed devices only. + Unmanaged devices can pose a security risk by allowing users to sync sensitive data to unauthorized devices, + potentially leading to data leakage or unauthorized access. + + The check fails if OneDrive sync is not restricted to managed devices (AllowedDomainGuidsForSyncApp is empty). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the OneDrive sync restriction check. + + Retrieves the OneDrive sync settings from the Microsoft 365 SharePoint client and + generates a report indicating whether OneDrive sync is restricted to managed devices only. + + Returns: + List[CheckReportM365]: A list containing the report object with the result of the check. + """ + findings = [] + settings = sharepoint_client.settings + if settings: + report = CheckReportM365( + self.metadata(), + resource=settings if settings else {}, + resource_name="SharePoint Settings", + resource_id=sharepoint_client.tenant_domain, + ) + report.status = "PASS" + report.status_extended = "Microsoft 365 SharePoint does not allow OneDrive sync to unmanaged devices." + + if len(settings.allowedDomainGuidsForSyncApp) == 0: + report.status = "FAIL" + report.status_extended = "Microsoft 365 SharePoint allows OneDrive sync to unmanaged devices." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/sharepoint/sharepoint_service.py b/prowler/providers/m365/services/sharepoint/sharepoint_service.py index 6040a321b8..02a701821f 100644 --- a/prowler/providers/m365/services/sharepoint/sharepoint_service.py +++ b/prowler/providers/m365/services/sharepoint/sharepoint_service.py @@ -1,3 +1,4 @@ +import uuid from asyncio import gather, get_event_loop from typing import List, Optional @@ -26,7 +27,6 @@ class SharePoint(M365Service): settings = None try: global_settings = await self.client.admin.sharepoint.settings.get() - settings = SharePointSettings( sharingCapability=( str(global_settings.sharing_capability).split(".")[-1] @@ -38,6 +38,7 @@ class SharePoint(M365Service): sharingDomainRestrictionMode=global_settings.sharing_domain_restriction_mode, legacyAuth=global_settings.is_legacy_auth_protocols_enabled, resharingEnabled=global_settings.is_resharing_by_external_users_enabled, + allowedDomainGuidsForSyncApp=global_settings.allowed_domain_guids_for_sync_app, ) except ODataError as error: @@ -60,3 +61,4 @@ class SharePointSettings(BaseModel): sharingDomainRestrictionMode: str resharingEnabled: bool legacyAuth: bool + allowedDomainGuidsForSyncApp: List[uuid.UUID] diff --git a/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py index 6111ff0993..0ba5bd69af 100644 --- a/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_managed/sharepoint_external_sharing_managed_test.py @@ -1,3 +1,4 @@ +import uuid from unittest import mock from prowler.providers.m365.services.sharepoint.sharepoint_service import ( @@ -35,6 +36,7 @@ class Test_sharepoint_external_sharing_managed: legacyAuth=True, resharingEnabled=False, sharingDomainRestrictionMode="none", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -80,6 +82,7 @@ class Test_sharepoint_external_sharing_managed: legacyAuth=True, resharingEnabled=False, sharingDomainRestrictionMode="allowList", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -125,6 +128,7 @@ class Test_sharepoint_external_sharing_managed: legacyAuth=True, resharingEnabled=False, sharingDomainRestrictionMode="blockList", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -170,6 +174,7 @@ class Test_sharepoint_external_sharing_managed: legacyAuth=True, resharingEnabled=False, sharingDomainRestrictionMode="allowList", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -215,6 +220,7 @@ class Test_sharepoint_external_sharing_managed: legacyAuth=True, resharingEnabled=False, sharingDomainRestrictionMode="blockList", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN diff --git a/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py index f238cbf4fa..beb1b4a52a 100644 --- a/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_external_sharing_restricted/sharepoint_external_sharing_restricted_test.py @@ -1,3 +1,4 @@ +import uuid from unittest import mock from prowler.providers.m365.services.sharepoint.sharepoint_service import ( @@ -35,6 +36,7 @@ class Test_sharepoint_external_sharing_restricted: sharingDomainRestrictionMode="allowList", resharingEnabled=False, legacyAuth=True, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -78,6 +80,7 @@ class Test_sharepoint_external_sharing_restricted: sharingDomainRestrictionMode="allowList", resharingEnabled=False, legacyAuth=True, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN diff --git a/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py b/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py index 1386278fa6..ba98f79477 100644 --- a/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_guest_sharing_restricted/sharepoint_guest_sharing_restricted_test.py @@ -1,3 +1,4 @@ +import uuid from unittest import mock from prowler.providers.m365.services.sharepoint.sharepoint_service import ( @@ -35,6 +36,7 @@ class Test_sharepoint_guest_sharing_restricted: sharingDomainRestrictionMode="allowList", legacyAuth=True, resharingEnabled=False, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -79,6 +81,7 @@ class Test_sharepoint_guest_sharing_restricted: sharingDomainRestrictionMode="allowList", legacyAuth=True, resharingEnabled=True, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN diff --git a/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py b/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py index bf2c23a645..43753558be 100644 --- a/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_modern_authentication_required/sharepoint_modern_authentication_required_test.py @@ -1,3 +1,4 @@ +import uuid from unittest import mock from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -35,6 +36,7 @@ class Test_sharepoint_modern_authentication_required: sharingDomainRestrictionMode="allowList", resharingEnabled=False, legacyAuth=False, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN @@ -81,6 +83,7 @@ class Test_sharepoint_modern_authentication_required: sharingDomainRestrictionMode="allowList", resharingEnabled=False, legacyAuth=True, + allowedDomainGuidsForSyncApp=[uuid.uuid4()], ) sharepoint_client.tenant_domain = DOMAIN diff --git a/tests/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices_test.py b/tests/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices_test.py new file mode 100644 index 0000000000..0788194f8a --- /dev/null +++ b/tests/providers/m365/services/sharepoint/sharepoint_onedrive_sync_restricted_unmanaged_devices/sharepoint_onedrive_sync_restricted_unmanaged_devices_test.py @@ -0,0 +1,129 @@ +import uuid +from unittest import mock + +from prowler.providers.m365.services.sharepoint.sharepoint_service import ( + SharePointSettings, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_sharepoint_onedrive_sync_restricted_unmanaged_devices: + def test_no_allowed_domain_guids(self): + """ + Test when there are no allowed domain guids for OneDrive sync app + + + """ + sharepoint_client = mock.MagicMock + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_client", + new=sharepoint_client, + ), + ): + from prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices import ( + sharepoint_onedrive_sync_restricted_unmanaged_devices, + ) + + sharepoint_client.settings = SharePointSettings( + sharingCapability="ExternalUserSharingOnly", + sharingAllowedDomainList=["allowed-domain.com"], + sharingBlockedDomainList=["blocked-domain.com"], + legacyAuth=True, + resharingEnabled=False, + sharingDomainRestrictionMode="none", + allowedDomainGuidsForSyncApp=[], + ) + sharepoint_client.tenant_domain = DOMAIN + + check = sharepoint_onedrive_sync_restricted_unmanaged_devices() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Microsoft 365 SharePoint allows OneDrive sync to unmanaged devices." + ) + assert result[0].resource_id == DOMAIN + assert result[0].location == "global" + assert result[0].resource_name == "SharePoint Settings" + assert result[0].resource == sharepoint_client.settings.dict() + + def test_allowed_domain_guids(self): + """ + Test when there are allowed domain guids for OneDrive sync app + """ + sharepoint_client = mock.MagicMock + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_client", + new=sharepoint_client, + ), + ): + from prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices import ( + sharepoint_onedrive_sync_restricted_unmanaged_devices, + ) + + sharepoint_client.settings = SharePointSettings( + sharingCapability="ExternalUserSharingOnly", + sharingAllowedDomainList=[], + sharingBlockedDomainList=["blocked-domain.com"], + legacyAuth=True, + resharingEnabled=False, + sharingDomainRestrictionMode="allowList", + allowedDomainGuidsForSyncApp=[uuid.uuid4()], + ) + sharepoint_client.tenant_domain = DOMAIN + + check = sharepoint_onedrive_sync_restricted_unmanaged_devices() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Microsoft 365 SharePoint does not allow OneDrive sync to unmanaged devices." + ) + assert result[0].resource_id == DOMAIN + assert result[0].location == "global" + assert result[0].resource_name == "SharePoint Settings" + assert result[0].resource == sharepoint_client.settings.dict() + + def test_empty_settings(self): + """ + Test when sharepoint_client.settings is empty: + The check should return an empty list of findings. + """ + sharepoint_client = mock.MagicMock + sharepoint_client.settings = {} + sharepoint_client.tenant_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_client", + new=sharepoint_client, + ), + ): + from prowler.providers.m365.services.sharepoint.sharepoint_onedrive_sync_restricted_unmanaged_devices.sharepoint_onedrive_sync_restricted_unmanaged_devices import ( + sharepoint_onedrive_sync_restricted_unmanaged_devices, + ) + + check = sharepoint_onedrive_sync_restricted_unmanaged_devices() + result = check.execute() + + assert len(result) == 0 diff --git a/tests/providers/m365/services/sharepoint/sharepoint_service_test.py b/tests/providers/m365/services/sharepoint/sharepoint_service_test.py index 8c3dc72598..3b67f06c28 100644 --- a/tests/providers/m365/services/sharepoint/sharepoint_service_test.py +++ b/tests/providers/m365/services/sharepoint/sharepoint_service_test.py @@ -1,3 +1,4 @@ +import uuid from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo @@ -7,6 +8,8 @@ from prowler.providers.m365.services.sharepoint.sharepoint_service import ( ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider +uuid_value = uuid.uuid4() + async def mock_sharepoint_get_settings(_): return SharePointSettings( @@ -16,6 +19,7 @@ async def mock_sharepoint_get_settings(_): sharingDomainRestrictionMode="allowList", resharingEnabled=False, legacyAuth=True, + allowedDomainGuidsForSyncApp=[uuid_value], ) @@ -39,3 +43,5 @@ class Test_SharePoint_Service: assert settings.sharingDomainRestrictionMode == "allowList" assert settings.resharingEnabled is False assert settings.legacyAuth is True + assert settings.allowedDomainGuidsForSyncApp == [uuid_value] + assert len(settings.allowedDomainGuidsForSyncApp) == 1 From 79b29d943759a30af1ebfa48a5dc757112cb18df Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:05:41 +0200 Subject: [PATCH 232/359] feat(exchange): add new check `exchange_mailbox_policy_additional_storage_restricted` (#7638) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 18 +++ .../__init__.py | 0 ...dditional_storage_restricted.metadata.json | 30 +++++ ...ox_policy_additional_storage_restricted.py | 44 +++++++ .../services/exchange/exchange_service.py | 25 ++++ ...licy_additional_storage_restricted_test.py | 118 ++++++++++++++++++ .../exchange/exchange_service_test.py | 28 +++++ 8 files changed, 264 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.py create mode 100644 tests/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 1c7cbc4175..09184ad5c4 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -37,6 +37,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) +- Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 982e26672b..91974a0b15 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -466,3 +466,21 @@ class M365PowerShell(PowerShellSession): return self.execute( "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + + def get_mailbox_policy(self) -> dict: + """ + Get Mailbox Policy. + + Retrieves the current mailbox policy settings for Exchange Online. + + Returns: + dict: Mailbox policy settings in JSON format. + + Example: + >>> get_mailbox_policy() + { + "Id": "OwaMailboxPolicy-Default", + "AdditionalStorageProvidersAvailable": True + } + """ + return self.execute("Get-OwaMailboxPolicy | ConvertTo-Json", json_parse=True) diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/__init__.py b/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.metadata.json b/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.metadata.json new file mode 100644 index 0000000000..1657d50dbd --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_mailbox_policy_additional_storage_restricted", + "CheckTitle": "Ensure additional storage providers are restricted in Outlook on the web.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Mailboxes Policy", + "Description": "Restrict the availability of additional storage providers (e.g., Box, Dropbox, Google Drive) in Outlook on the web to prevent users from accessing external storage services through the OWA interface.", + "Risk": "Allowing users to access third-party storage providers from Outlook on the web increases the risk of data exfiltration and exposure to untrusted content or malware.", + "RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-owamailboxpolicy?view=exchange-ps", + "Remediation": { + "Code": { + "CLI": "Set-OwaMailboxPolicy -Identity OwaMailboxPolicy-Default -AdditionalStorageProvidersAvailable $false", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable access to additional storage providers in Outlook on the web to reduce the risk of data leakage.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-owamailboxpolicy?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.py b/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.py new file mode 100644 index 0000000000..05ecd7cc0d --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted.py @@ -0,0 +1,44 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_mailbox_policy_additional_storage_restricted(Check): + """Check if Exchange mailbox policy restricts additional storage providers. + + This check ensures that the mailbox policy does not allow additional storage providers. + """ + + def execute(self) -> List[CheckReportM365]: + """Run the check to validate Exchange mailbox policy restrictions. + + Iterates through the mailbox policy configuration to determine if additional storage + providers are restricted and generates a report based on the policy status. + + Returns: + List[CheckReportM365]: A list of reports with the restriction status for the mailbox policy. + """ + findings = [] + mailbox_policy = exchange_client.mailbox_policy + if mailbox_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=mailbox_policy, + resource_name="Exchange Mailbox Policy", + resource_id=mailbox_policy.id, + ) + report.status = "FAIL" + report.status_extended = ( + "Exchange mailbox policy allows additional storage providers." + ) + + if not mailbox_policy.additional_storage_enabled: + report.status = "PASS" + report.status_extended = ( + "Exchange mailbox policy restricts additional storage providers." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 5bd8cada6a..dbcc44499f 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -14,6 +14,7 @@ class Exchange(M365Service): self.mailboxes_config = [] self.external_mail_config = [] self.transport_rules = [] + self.mailbox_policy = None if self.powershell: self.powershell.connect_exchange_online() @@ -21,6 +22,7 @@ class Exchange(M365Service): self.mailboxes_config = self._get_mailbox_audit_config() self.external_mail_config = self._get_external_mail_config() self.transport_rules = self._get_transport_rules() + self.mailbox_policy = self._get_mailbox_policy() self.powershell.close() def _get_organization_config(self): @@ -112,6 +114,24 @@ class Exchange(M365Service): ) return transport_rules + def _get_mailbox_policy(self): + logger.info("Microsoft365 - Getting mailbox policy configuration...") + mailboxes_policy = None + try: + mailbox_policy = self.powershell.get_mailbox_policy() + if mailbox_policy: + mailboxes_policy = MailboxPolicy( + id=mailbox_policy.get("Id", ""), + additional_storage_enabled=mailbox_policy.get( + "AdditionalStorageProvidersAvailable", True + ), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return mailboxes_policy + class Organization(BaseModel): name: str @@ -134,3 +154,8 @@ class TransportRule(BaseModel): name: str scl: Optional[int] sender_domain_is: list[str] + + +class MailboxPolicy(BaseModel): + id: str + additional_storage_enabled: bool diff --git a/tests/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted_test.py b/tests/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted_test.py new file mode 100644 index 0000000000..688d68add6 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_mailbox_policy_additional_storage_restricted/exchange_mailbox_policy_additional_storage_restricted_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_mailbox_policy_additional_storage_restricted: + def test_mailbox_policy_restricts_additional_storage(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted import ( + exchange_mailbox_policy_additional_storage_restricted, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + MailboxPolicy, + ) + + exchange_client.mailbox_policy = MailboxPolicy( + id="OwaMailboxPolicy-Default", additional_storage_enabled=False + ) + + check = exchange_mailbox_policy_additional_storage_restricted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Exchange mailbox policy restricts additional storage providers." + ) + assert result[0].resource == exchange_client.mailbox_policy.dict() + assert result[0].resource_name == "Exchange Mailbox Policy" + assert result[0].resource_id == "OwaMailboxPolicy-Default" + assert result[0].location == "global" + + def test_mailbox_policy_allows_additional_storage(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted import ( + exchange_mailbox_policy_additional_storage_restricted, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + MailboxPolicy, + ) + + exchange_client.mailbox_policy = MailboxPolicy( + id="OwaMailboxPolicy-Default", additional_storage_enabled=True + ) + + check = exchange_mailbox_policy_additional_storage_restricted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Exchange mailbox policy allows additional storage providers." + ) + assert result[0].resource == exchange_client.mailbox_policy.dict() + assert result[0].resource_name == "Exchange Mailbox Policy" + assert result[0].resource_id == "OwaMailboxPolicy-Default" + assert result[0].location == "global" + + def test_no_mailbox_policy(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.mailbox_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted import ( + exchange_mailbox_policy_additional_storage_restricted, + ) + + check = exchange_mailbox_policy_additional_storage_restricted() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 8131157265..42cc16a507 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, ExternalMailConfig, MailboxAuditConfig, + MailboxPolicy, Organization, TransportRule, ) @@ -51,6 +52,13 @@ def mock_exchange_get_transport_rules(_): ] +def mock_exchange_get_mailbox_policy(_): + return MailboxPolicy( + id="test", + additional_storage_enabled=True, + ) + + class Test_Exchange_Service: def test_get_client(self): with ( @@ -163,3 +171,23 @@ class Test_Exchange_Service: assert transport_rules[1].sender_domain_is == ["example.com"] exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_mailbox_policy", + new=mock_exchange_get_mailbox_policy, + ) + def test_get_mailbox_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + mailbox_policy = exchange_client.mailbox_policy + assert mailbox_policy.id == "test" + assert mailbox_policy.additional_storage_enabled is True + exchange_client.powershell.close() From c56bd519bb10a429681cc76321d2a27ee722a27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Wed, 30 Apr 2025 12:36:25 +0200 Subject: [PATCH 233/359] test(performance): Add base framework for API performance tests (#7632) --- api/tests/performance/__init__.py | 0 api/tests/performance/benchmark.py | 156 +++++++++++++++ api/tests/performance/requirements.txt | 2 + api/tests/performance/scenarios/__init__.py | 0 api/tests/performance/scenarios/findings.py | 202 ++++++++++++++++++++ api/tests/performance/utils/__init__.py | 0 api/tests/performance/utils/config.py | 19 ++ api/tests/performance/utils/helpers.py | 168 ++++++++++++++++ 8 files changed, 547 insertions(+) create mode 100644 api/tests/performance/__init__.py create mode 100644 api/tests/performance/benchmark.py create mode 100644 api/tests/performance/requirements.txt create mode 100644 api/tests/performance/scenarios/__init__.py create mode 100644 api/tests/performance/scenarios/findings.py create mode 100644 api/tests/performance/utils/__init__.py create mode 100644 api/tests/performance/utils/config.py create mode 100644 api/tests/performance/utils/helpers.py diff --git a/api/tests/performance/__init__.py b/api/tests/performance/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/performance/benchmark.py b/api/tests/performance/benchmark.py new file mode 100644 index 0000000000..1df7f81645 --- /dev/null +++ b/api/tests/performance/benchmark.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +import argparse +import re +import subprocess +import sys +from pathlib import Path + +import matplotlib.pyplot as plt +import pandas as pd + +plt.style.use("ggplot") + + +def run_locust( + locust_file: str, + host: str, + users: int, + hatch_rate: int, + run_time: str, + csv_prefix: Path, +) -> Path: + artifacts_dir = Path("artifacts") + artifacts_dir.mkdir(parents=True, exist_ok=True) + + cmd = [ + "locust", + "-f", + f"scenarios/{locust_file}", + "--headless", + "-u", + str(users), + "-r", + str(hatch_rate), + "-t", + run_time, + "--host", + host, + "--csv", + str(artifacts_dir / csv_prefix.name), + ] + print(f"Running Locust: {' '.join(cmd)}") + process = subprocess.run(cmd) + if process.returncode: + sys.exit("Locust execution failed") + + stats_file = artifacts_dir / f"{csv_prefix.stem}_stats.csv" + if not stats_file.exists(): + sys.exit(f"Stats CSV not found: {stats_file}") + return stats_file + + +def load_percentiles(csv_path: Path) -> pd.DataFrame: + df = pd.read_csv(csv_path) + mapping = {"50%": "p50", "75%": "p75", "90%": "p90", "95%": "p95"} + available = [col for col in mapping if col in df.columns] + renamed = {col: mapping[col] for col in available} + df = df.rename(columns=renamed).set_index("Name")[renamed.values()] + return df.drop(index=["Aggregated"], errors="ignore") + + +def sanitize_label(label: str) -> str: + text = re.sub(r"[^\w]+", "_", label.strip().lower()) + return text.strip("_") + + +def plot_multi_comparison(metrics: dict[str, pd.DataFrame]) -> None: + common = sorted(set.intersection(*(set(df.index) for df in metrics.values()))) + percentiles = list(next(iter(metrics.values())).columns) + groups = len(metrics) + width = 0.8 / groups + + for endpoint in common: + fig, ax = plt.subplots(figsize=(10, 5), dpi=100) + for idx, (label, df) in enumerate(metrics.items()): + series = df.loc[endpoint] + positions = [ + i + (idx - groups / 2) * width + width / 2 + for i in range(len(percentiles)) + ] + bars = ax.bar(positions, series.values, width, label=label) + for bar in bars: + height = bar.get_height() + ax.annotate( + f"{int(height)}", + xy=(bar.get_x() + bar.get_width() / 2, height), + xytext=(0, 3), + textcoords="offset points", + ha="center", + va="bottom", + fontsize=8, + ) + + ax.set_xticks(range(len(percentiles))) + ax.set_xticklabels(percentiles) + ax.set_ylabel("Latency (ms)") + ax.set_title(endpoint, fontsize=12) + ax.grid(True, axis="y", linestyle="--", alpha=0.7) + + fig.tight_layout() + fig.subplots_adjust(right=0.75) + ax.legend(loc="center left", bbox_to_anchor=(1, 0.5), framealpha=0.9) + + output = Path("artifacts") / f"comparison_{sanitize_label(endpoint)}.png" + plt.savefig(output) + plt.close(fig) + print(f"Saved chart: {output}") + + +def main() -> None: + parser = argparse.ArgumentParser(description="Run Locust and compare metrics") + parser.add_argument("--locustfile", required=True, help="Locust file in scenarios/") + parser.add_argument("--host", required=True, help="Target host URL") + parser.add_argument( + "--users", type=int, default=10, help="Number of simulated users" + ) + parser.add_argument("--rate", type=int, default=1, help="Hatch rate per second") + parser.add_argument("--time", default="1m", help="Test duration (e.g. 30s, 1m)") + parser.add_argument( + "--metrics-dir", default="baselines", help="Directory with CSV baselines" + ) + parser.add_argument("--version", default="current", help="Test version") + args = parser.parse_args() + + metrics_dir = Path(args.metrics_dir) + if not metrics_dir.is_dir(): + sys.exit(f"Metrics directory not found: {metrics_dir}") + + metrics_data: dict[str, pd.DataFrame] = {} + for csv_file in sorted(metrics_dir.glob("*.csv")): + metrics_data[csv_file.stem] = load_percentiles(csv_file) + + current_prefix = Path(args.version) + current_csv = run_locust( + locust_file=args.locustfile, + host=args.host, + users=args.users, + hatch_rate=args.rate, + run_time=args.time, + csv_prefix=current_prefix, + ) + metrics_data[args.version] = load_percentiles(current_csv) + + for endpoint in sorted( + set.intersection(*(set(df.index) for df in metrics_data.values())) + ): + parts = [endpoint] + for label, df in metrics_data.items(): + s = df.loc[endpoint] + parts.append(f"{label}: p50 {s.p50}, p75 {s.p75}, p90 {s.p90}, p95 {s.p95}") + print(" | ".join(parts)) + + plot_multi_comparison(metrics_data) + + +if __name__ == "__main__": + main() diff --git a/api/tests/performance/requirements.txt b/api/tests/performance/requirements.txt new file mode 100644 index 0000000000..139690df29 --- /dev/null +++ b/api/tests/performance/requirements.txt @@ -0,0 +1,2 @@ +locust==2.34.1 +matplotlib==3.10.1 diff --git a/api/tests/performance/scenarios/__init__.py b/api/tests/performance/scenarios/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/performance/scenarios/findings.py b/api/tests/performance/scenarios/findings.py new file mode 100644 index 0000000000..aef484a7ea --- /dev/null +++ b/api/tests/performance/scenarios/findings.py @@ -0,0 +1,202 @@ +from locust import events, task +from utils.config import ( + FINDINGS_UI_SORT_VALUES, + L_PROVIDER_NAME, + M_PROVIDER_NAME, + S_PROVIDER_NAME, + TARGET_INSERTED_AT, +) +from utils.helpers import ( + APIUserBase, + get_api_token, + get_auth_headers, + get_next_resource_filter, + get_resource_filters_pairs, + get_scan_id_from_provider_name, + get_sort_value, +) + +GLOBAL = { + "token": None, + "scan_ids": {}, + "resource_filters": None, + "large_resource_filters": None, +} + + +@events.test_start.add_listener +def on_test_start(environment, **kwargs): + GLOBAL["token"] = get_api_token(environment.host) + + GLOBAL["scan_ids"]["small"] = get_scan_id_from_provider_name( + environment.host, GLOBAL["token"], S_PROVIDER_NAME + ) + GLOBAL["scan_ids"]["medium"] = get_scan_id_from_provider_name( + environment.host, GLOBAL["token"], M_PROVIDER_NAME + ) + GLOBAL["scan_ids"]["large"] = get_scan_id_from_provider_name( + environment.host, GLOBAL["token"], L_PROVIDER_NAME + ) + + GLOBAL["resource_filters"] = get_resource_filters_pairs( + environment.host, GLOBAL["token"] + ) + GLOBAL["large_resource_filters"] = get_resource_filters_pairs( + environment.host, GLOBAL["token"], GLOBAL["scan_ids"]["large"] + ) + + +class APIUser(APIUserBase): + def on_start(self): + self.token = GLOBAL["token"] + self.s_scan_id = GLOBAL["scan_ids"]["small"] + self.m_scan_id = GLOBAL["scan_ids"]["medium"] + self.l_scan_id = GLOBAL["scan_ids"]["large"] + self.available_resource_filters = GLOBAL["resource_filters"] + self.available_resource_filters_large_scan = GLOBAL["large_resource_filters"] + + @task + def findings_default(self): + name = "/findings" + page_number = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page_number}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[inserted_at]={TARGET_INSERTED_AT}" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task(3) + def findings_default_include(self): + name = "/findings?include" + page = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[inserted_at]={TARGET_INSERTED_AT}" + f"&include=scan.provider,resources" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task(3) + def findings_metadata(self): + endpoint = f"/findings/metadata?" f"filter[inserted_at]={TARGET_INSERTED_AT}" + self.client.get( + endpoint, headers=get_auth_headers(self.token), name="/findings/metadata" + ) + + @task + def findings_scan_small(self): + name = "/findings?filter[scan_id] - 50k" + page_number = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page_number}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[scan]={self.s_scan_id}" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task + def findings_metadata_scan_small(self): + endpoint = f"/findings/metadata?" f"&filter[scan]={self.s_scan_id}" + self.client.get( + endpoint, + headers=get_auth_headers(self.token), + name="/findings/metadata?filter[scan_id] - 50k", + ) + + @task(2) + def findings_scan_medium(self): + name = "/findings?filter[scan_id] - 250k" + page_number = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page_number}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[scan]={self.m_scan_id}" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task + def findings_metadata_scan_medium(self): + endpoint = f"/findings/metadata?" f"&filter[scan]={self.m_scan_id}" + self.client.get( + endpoint, + headers=get_auth_headers(self.token), + name="/findings/metadata?filter[scan_id] - 250k", + ) + + @task + def findings_scan_large(self): + name = "/findings?filter[scan_id] - 500k" + page_number = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page_number}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[scan]={self.l_scan_id}" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task + def findings_scan_large_include(self): + name = "/findings?filter[scan_id]&include - 500k" + page_number = self._next_page(name) + endpoint = ( + f"/findings?page[number]={page_number}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[scan]={self.l_scan_id}" + f"&include=scan.provider,resources" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task + def findings_metadata_scan_large(self): + endpoint = f"/findings/metadata?" f"&filter[scan]={self.l_scan_id}" + self.client.get( + endpoint, + headers=get_auth_headers(self.token), + name="/findings/metadata?filter[scan_id] - 500k", + ) + + @task(2) + def findings_resource_filter(self): + name = "/findings?filter[resource_filter]&include" + filter_name, filter_value = get_next_resource_filter( + self.available_resource_filters + ) + + endpoint = ( + f"/findings?filter[{filter_name}]={filter_value}" + f"&filter[inserted_at]={TARGET_INSERTED_AT}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&include=scan.provider,resources" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task(3) + def findings_metadata_resource_filter(self): + name = "/findings/metadata?filter[resource_filter]" + filter_name, filter_value = get_next_resource_filter( + self.available_resource_filters + ) + + endpoint = ( + f"/findings?filter[{filter_name}]={filter_value}" + f"&filter[inserted_at]={TARGET_INSERTED_AT}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) + + @task + def findings_resource_filter_large_scan_include(self): + name = "/findings?filter[resource_filter][scan]&include - 500k" + filter_name, filter_value = get_next_resource_filter( + self.available_resource_filters + ) + + endpoint = ( + f"/findings?filter[{filter_name}]={filter_value}" + f"&{get_sort_value(FINDINGS_UI_SORT_VALUES)}" + f"&filter[scan]={self.l_scan_id}" + f"&include=scan.provider,resources" + ) + self.client.get(endpoint, headers=get_auth_headers(self.token), name=name) diff --git a/api/tests/performance/utils/__init__.py b/api/tests/performance/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/performance/utils/config.py b/api/tests/performance/utils/config.py new file mode 100644 index 0000000000..febc5e0a24 --- /dev/null +++ b/api/tests/performance/utils/config.py @@ -0,0 +1,19 @@ +import os + +USER_EMAIL = os.environ.get("USER_EMAIL") +USER_PASSWORD = os.environ.get("USER_PASSWORD") + +BASE_HEADERS = {"Content-Type": "application/vnd.api+json"} + +FINDINGS_UI_SORT_VALUES = ["severity", "status", "-inserted_at"] +TARGET_INSERTED_AT = os.environ.get("TARGET_INSERTED_AT", "2025-04-22") + +FINDINGS_RESOURCE_METADATA = { + "regions": "region", + "resource_types": "resource_type", + "services": "service", +} + +S_PROVIDER_NAME = "provider-50k" +M_PROVIDER_NAME = "provider-250k" +L_PROVIDER_NAME = "provider-500k" diff --git a/api/tests/performance/utils/helpers.py b/api/tests/performance/utils/helpers.py new file mode 100644 index 0000000000..999a2d55c8 --- /dev/null +++ b/api/tests/performance/utils/helpers.py @@ -0,0 +1,168 @@ +import random +from collections import defaultdict +from threading import Lock + +import requests +from locust import HttpUser, between +from utils.config import ( + BASE_HEADERS, + FINDINGS_RESOURCE_METADATA, + TARGET_INSERTED_AT, + USER_EMAIL, + USER_PASSWORD, +) + +_global_page_counters = defaultdict(int) +_page_lock = Lock() + + +class APIUserBase(HttpUser): + """ + Base class for API user simulation in Locust performance tests. + + Attributes: + abstract (bool): Indicates this is an abstract user class. + wait_time: Time between task executions, randomized between 1 and 5 seconds. + """ + + abstract = True + wait_time = between(1, 5) + + def _next_page(self, endpoint_name: str) -> int: + """ + Returns the next page number for a given endpoint. Thread-safe. + + Args: + endpoint_name (str): Name of the API endpoint being paginated. + + Returns: + int: The next page number for the given endpoint. + """ + with _page_lock: + _global_page_counters[endpoint_name] += 1 + return _global_page_counters[endpoint_name] + + +def get_next_resource_filter(available_values: dict) -> tuple: + """ + Randomly selects a filter type and value from available options. + + Args: + available_values (dict): Dictionary with filter types as keys and list of possible values. + + Returns: + tuple: A (filter_type, filter_value) pair randomly selected. + """ + filter_type = random.choice(list(available_values.keys())) + filter_value = random.choice(available_values[filter_type]) + return filter_type, filter_value + + +def get_auth_headers(token: str) -> dict: + """ + Returns the headers for the API requests. + + Args: + token (str): The token to be included in the headers. + + Returns: + dict: The headers for the API requests. + """ + return { + "Authorization": f"Bearer {token}", + **BASE_HEADERS, + } + + +def get_api_token(host: str) -> str: + """ + Authenticates with the API and retrieves a bearer token. + + Args: + host (str): The host URL of the API. + + Returns: + str: The access token for authenticated requests. + + Raises: + AssertionError: If the request fails or does not return a 200 status code. + """ + login_payload = { + "data": { + "type": "tokens", + "attributes": {"email": USER_EMAIL, "password": USER_PASSWORD}, + } + } + response = requests.post(f"{host}/tokens", json=login_payload, headers=BASE_HEADERS) + assert response.status_code == 200, f"Failed to get token: {response.text}" + return response.json()["data"]["attributes"]["access"] + + +def get_scan_id_from_provider_name(host: str, token: str, provider_name: str) -> str: + """ + Retrieves the scan ID associated with a specific provider name. + + Args: + host (str): The host URL of the API. + token (str): Bearer token for authentication. + provider_name (str): Name of the provider to filter scans by. + + Returns: + str: The ID of the scan. + + Raises: + AssertionError: If the request fails or does not return a 200 status code. + """ + response = requests.get( + f"{host}/scans?fields[scans]=id&filter[provider_alias]={provider_name}", + headers=get_auth_headers(token), + ) + assert response.status_code == 200, f"Failed to get scan: {response.text}" + return response.json()["data"][0]["id"] + + +def get_resource_filters_pairs(host: str, token: str, scan_id: str = "") -> dict: + """ + Retrieves and maps resource metadata filter values from the findings endpoint. + + Args: + host (str): The host URL of the API. + token (str): Bearer token for authentication. + scan_id (str, optional): Optional scan ID to filter metadata. Defaults to using inserted_at timestamp. + + Returns: + dict: A dictionary of resource filter metadata. + + Raises: + AssertionError: If the request fails or does not return a 200 status code. + """ + metadata_filters = ( + f"filter[scan]={scan_id}" + if scan_id + else f"filter[inserted_at]={TARGET_INSERTED_AT}" + ) + response = requests.get( + f"{host}/findings/metadata?{metadata_filters}", headers=get_auth_headers(token) + ) + assert ( + response.status_code == 200 + ), f"Failed to get resource filters values: {response.text}" + attributes = response.json()["data"]["attributes"] + return { + FINDINGS_RESOURCE_METADATA[key]: values + for key, values in attributes.items() + if key in FINDINGS_RESOURCE_METADATA.keys() + } + + +def get_sort_value(sort_values: list) -> str: + """ + Constructs a sort query string from a list of sort keys. + + Args: + sort_values (list): The list of sort values to include in the query. + + Returns: + str: A formatted sort query string (e.g., "sort=created_at,-severity"). + """ + return f"sort={','.join(sort_values)}" From fe42bb47f7067917c5ad5cd34ea85a03fc61091e Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 30 Apr 2025 13:00:45 +0200 Subject: [PATCH 234/359] fix: set correct default value for session duration (#7639) --- ui/components/providers/workflow/forms/update-via-role-form.tsx | 2 +- ui/components/providers/workflow/forms/via-role-form.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/components/providers/workflow/forms/update-via-role-form.tsx b/ui/components/providers/workflow/forms/update-via-role-form.tsx index 85e00e3cb1..c0d9c24917 100644 --- a/ui/components/providers/workflow/forms/update-via-role-form.tsx +++ b/ui/components/providers/workflow/forms/update-via-role-form.tsx @@ -54,7 +54,7 @@ export const UpdateViaRoleForm = ({ aws_secret_access_key: "", aws_session_token: "", role_session_name: "", - session_duration: 3600, + session_duration: "3600", }), }, }); diff --git a/ui/components/providers/workflow/forms/via-role-form.tsx b/ui/components/providers/workflow/forms/via-role-form.tsx index 917f049c7c..3bed8d3af7 100644 --- a/ui/components/providers/workflow/forms/via-role-form.tsx +++ b/ui/components/providers/workflow/forms/via-role-form.tsx @@ -59,7 +59,7 @@ export const ViaRoleForm = ({ aws_secret_access_key: "", aws_session_token: "", role_session_name: "", - session_duration: 3600, + session_duration: "3600", } : {}), }, From de01087246fe7cca8df2e4b41ff4ac51757bff8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 30 Apr 2025 16:03:23 +0200 Subject: [PATCH 235/359] fix(s3): add ContentType in upload_file (#7635) Co-authored-by: Pepe Fagoaga --- prowler/CHANGELOG.md | 1 + prowler/providers/aws/lib/s3/s3.py | 14 +++++++++++++- tests/providers/aws/lib/s3/s3_test.py | 10 +++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 09184ad5c4..34601abebf 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -49,6 +49,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Improve compliance and dashboard [(#7596)](https://github.com/prowler-cloud/prowler/pull/7596) - Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) - Remove first empty line in HTML output [(#7606)](https://github.com/prowler-cloud/prowler/pull/7606) +- Ensure that ContentType in upload_file matches the uploaded file’s format [(#7635)](https://github.com/prowler-cloud/prowler/pull/7635) --- diff --git a/prowler/providers/aws/lib/s3/s3.py b/prowler/providers/aws/lib/s3/s3.py index f399171c98..03308224fe 100644 --- a/prowler/providers/aws/lib/s3/s3.py +++ b/prowler/providers/aws/lib/s3/s3.py @@ -105,6 +105,12 @@ class S3: """ try: uploaded_objects = {"success": {}, "failure": {}} + extension_to_content_type = { + ".html": "text/html", + ".csv": "text/csv", + ".ocsf.json": "application/json", + ".asff.json": "application/json", + } # Keys are regular and/or compliance for key, output_list in outputs.items(): for output in output_list: @@ -115,6 +121,7 @@ class S3: bucket_directory = self.get_object_path(self._output_directory) basename = path.basename(output.file_descriptor.name) + file_extension = output.file_extension if key == "compliance": object_name = f"{bucket_directory}/{key}/{basename}" @@ -128,7 +135,12 @@ class S3: # into the local filesystem because S3 upload file is the recommended way. # https://aws.amazon.com/blogs/developer/uploading-files-to-amazon-s3/ self._session.upload_file( - output.file_descriptor.name, self._bucket_name, object_name + Filename=output.file_descriptor.name, + Bucket=self._bucket_name, + Key=object_name, + ExtraArgs={ + "ContentType": extension_to_content_type[file_extension] + }, ) if output.file_extension in uploaded_objects["success"]: diff --git a/tests/providers/aws/lib/s3/s3_test.py b/tests/providers/aws/lib/s3/s3_test.py index 2cede7364d..34c906d69d 100644 --- a/tests/providers/aws/lib/s3/s3_test.py +++ b/tests/providers/aws/lib/s3/s3_test.py @@ -93,7 +93,7 @@ class TestS3: Bucket=S3_BUCKET_NAME, Key=uploaded_object_name, )["ContentType"] - == "binary/octet-stream" + == "text/csv" ) @mock_aws @@ -132,7 +132,7 @@ class TestS3: Bucket=S3_BUCKET_NAME, Key=uploaded_object_name, )["ContentType"] - == "binary/octet-stream" + == "text/csv" ) remove(f"{CURRENT_DIRECTORY}/{csv_file}") @@ -171,7 +171,7 @@ class TestS3: Bucket=S3_BUCKET_NAME, Key=uploaded_object_name, )["ContentType"] - == "binary/octet-stream" + == "application/json" ) @mock_aws @@ -209,7 +209,7 @@ class TestS3: Bucket=S3_BUCKET_NAME, Key=uploaded_object_name, )["ContentType"] - == "binary/octet-stream" + == "text/html" ) @mock_aws @@ -290,7 +290,7 @@ class TestS3: Bucket=S3_BUCKET_NAME, Key=uploaded_object_name, )["ContentType"] - == "binary/octet-stream" + == "text/csv" ) def test_get_get_object_path_with_prowler(self): From 3fd9c510863de770fae6d93b48f008cd983cc087 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:41:59 +0200 Subject: [PATCH 236/359] feat(m365): automate `PowerShell` modules installation (#7618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Adrián Jesús Peña Rodríguez --- Dockerfile | 41 ++- api/Dockerfile | 41 ++- prowler/lib/powershell/powershell.py | 7 +- prowler/providers/common/provider.py | 1 + .../providers/m365/lib/arguments/arguments.py | 13 +- .../m365/lib/powershell/m365_powershell.py | 92 +++++-- prowler/providers/m365/m365_provider.py | 14 +- .../lib/powershell/m365_powershell_test.py | 233 +++++++++++++++++- tests/providers/m365/m365_provider_test.py | 92 ++++++- 9 files changed, 479 insertions(+), 55 deletions(-) diff --git a/Dockerfile b/Dockerfile index eb79e31cce..0e9fb89a03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,43 @@ -FROM python:3.12.10-alpine3.20 +FROM python:3.12.10-slim-bookworm AS build LABEL maintainer="https://github.com/prowler-cloud/prowler" LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler" -# Update system dependencies and install essential tools -#hadolint ignore=DL3018 -RUN apk --no-cache upgrade && apk --no-cache add curl git gcc python3-dev musl-dev linux-headers +ARG POWERSHELL_VERSION=7.5.0 + +# hadolint ignore=DL3008 +RUN apt-get update && apt-get install -y --no-install-recommends wget libicu72 \ + && rm -rf /var/lib/apt/lists/* + +# Install PowerShell +RUN ARCH=$(uname -m) && \ + if [ "$ARCH" = "x86_64" ]; then \ + wget --progress=dot:giga https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-x64.tar.gz -O /tmp/powershell.tar.gz ; \ + elif [ "$ARCH" = "aarch64" ]; then \ + wget --progress=dot:giga https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-arm64.tar.gz -O /tmp/powershell.tar.gz ; \ + else \ + echo "Unsupported architecture: $ARCH" && exit 1 ; \ + fi && \ + mkdir -p /opt/microsoft/powershell/7 && \ + tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 && \ + chmod +x /opt/microsoft/powershell/7/pwsh && \ + ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && \ + rm /tmp/powershell.tar.gz + +# Add prowler user +RUN addgroup --gid 1000 prowler && \ + adduser --uid 1000 --gid 1000 --disabled-password --gecos "" prowler -# Create non-root user -RUN mkdir -p /home/prowler && \ - echo 'prowler:x:1000:1000:prowler:/home/prowler:' > /etc/passwd && \ - echo 'prowler:x:1000:' > /etc/group && \ - chown -R prowler:prowler /home/prowler USER prowler -# Copy necessary files WORKDIR /home/prowler + +# Copy necessary files COPY prowler/ /home/prowler/prowler/ COPY dashboard/ /home/prowler/dashboard/ COPY pyproject.toml /home/prowler COPY README.md /home/prowler/ +COPY prowler/providers/m365/lib/powershell/m365_powershell.py /home/prowler/prowler/providers/m365/lib/powershell/m365_powershell.py # Install Python dependencies ENV HOME='/home/prowler' @@ -35,6 +53,9 @@ RUN pip install --no-cache-dir --upgrade pip && \ RUN poetry install --compile && \ rm -rf ~/.cache/pip +# Install PowerShell modules +RUN poetry run python prowler/providers/m365/lib/powershell/m365_powershell.py + # Remove deprecated dash dependencies RUN pip uninstall dash-html-components -y && \ pip uninstall dash-core-components -y diff --git a/api/Dockerfile b/api/Dockerfile index 3569d003e7..cf0fb37556 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,13 +1,33 @@ -FROM python:3.12.8-alpine3.20 AS build +FROM python:3.12.10-slim-bookworm AS build LABEL maintainer="https://github.com/prowler-cloud/api" -# hadolint ignore=DL3018 -RUN apk --no-cache add gcc python3-dev musl-dev linux-headers curl-dev +ARG POWERSHELL_VERSION=7.5.0 +ENV POWERSHELL_VERSION=${POWERSHELL_VERSION} + +# hadolint ignore=DL3008 +RUN apt-get update && apt-get install -y --no-install-recommends wget libicu72 \ + && rm -rf /var/lib/apt/lists/* + +# Install PowerShell +RUN ARCH=$(uname -m) && \ + if [ "$ARCH" = "x86_64" ]; then \ + wget --progress=dot:giga https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-x64.tar.gz -O /tmp/powershell.tar.gz ; \ + elif [ "$ARCH" = "aarch64" ]; then \ + wget --progress=dot:giga https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-arm64.tar.gz -O /tmp/powershell.tar.gz ; \ + else \ + echo "Unsupported architecture: $ARCH" && exit 1 ; \ + fi && \ + mkdir -p /opt/microsoft/powershell/7 && \ + tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 && \ + chmod +x /opt/microsoft/powershell/7/pwsh && \ + ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && \ + rm /tmp/powershell.tar.gz + +# Add prowler user +RUN addgroup --gid 1000 prowler && \ + adduser --uid 1000 --gid 1000 --disabled-password --gecos "" prowler -RUN apk --no-cache upgrade && \ - addgroup -g 1000 prowler && \ - adduser -D -u 1000 -G prowler prowler USER prowler WORKDIR /home/prowler @@ -27,18 +47,13 @@ RUN poetry install --no-root && \ COPY docker-entrypoint.sh ./docker-entrypoint.sh +RUN poetry run python "$(poetry env info --path)/src/prowler/prowler/providers/m365/lib/powershell/m365_powershell.py" + WORKDIR /home/prowler/backend # Development image -# hadolint ignore=DL3006 FROM build AS dev -USER 0 -# hadolint ignore=DL3018 -RUN apk --no-cache add curl vim - -USER prowler - ENTRYPOINT ["../docker-entrypoint.sh", "dev"] # Production image diff --git a/prowler/lib/powershell/powershell.py b/prowler/lib/powershell/powershell.py index 26cd2fe952..1e13a74306 100644 --- a/prowler/lib/powershell/powershell.py +++ b/prowler/lib/powershell/powershell.py @@ -191,8 +191,11 @@ class PowerShellSession: error_thread.daemon = True error_thread.start() - result = result_queue.get(timeout=timeout) or default - error_result = error_queue.get(timeout=1) + try: + result = result_queue.get(timeout=timeout) or default + error_result = error_queue.get(timeout=1) or None + except queue.Empty: + result = default if error_result: logger.error(f"PowerShell error output: {error_result}") diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 0efde909ef..aaa94b21d1 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -221,6 +221,7 @@ class Provider(ABC): az_cli_auth=arguments.az_cli_auth, browser_auth=arguments.browser_auth, tenant_id=arguments.tenant_id, + init_modules=arguments.init_modules, fixer_config=fixer_config, ) elif "nhn" in provider_class_name.lower(): diff --git a/prowler/providers/m365/lib/arguments/arguments.py b/prowler/providers/m365/lib/arguments/arguments.py index a1980c4bd9..e88ef7982b 100644 --- a/prowler/providers/m365/lib/arguments/arguments.py +++ b/prowler/providers/m365/lib/arguments/arguments.py @@ -35,16 +35,9 @@ def init_parser(self): help="Microsoft 365 Tenant ID to be used with --browser-auth option", ) m365_parser.add_argument( - "--user", - nargs="?", - default=None, - help="Microsoft 365 user email", - ) - m365_parser.add_argument( - "--encypted-password", - nargs="?", - default=None, - help="Microsoft 365 encrypted password", + "--init-modules", + action="store_true", + help="Initialize Microsoft 365 PowerShell modules", ) # Regions m365_regions_subparser = m365_parser.add_argument_group("Regions") diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 91974a0b15..df4a26dfd8 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -2,6 +2,7 @@ import os import msal +from prowler.lib.logger import logger from prowler.lib.powershell.powershell import PowerShellSession from prowler.providers.m365.exceptions.exceptions import ( M365UserNotBelongingToTenantError, @@ -26,6 +27,7 @@ class M365PowerShell(PowerShellSession): Attributes: credentials (M365Credentials): The Microsoft 365 credentials used for authentication. + required_modules (list): List of required PowerShell modules for M365 operations. Note: This class requires the Microsoft Teams and Exchange Online PowerShell modules @@ -371,6 +373,24 @@ class M365PowerShell(PowerShellSession): "Get-MailboxAuditBypassAssociation | ConvertTo-Json", json_parse=True ) + def get_mailbox_policy(self) -> dict: + """ + Get Mailbox Policy. + + Retrieves the current mailbox policy settings for Exchange Online. + + Returns: + dict: Mailbox policy settings in JSON format. + + Example: + >>> get_mailbox_policy() + { + "Id": "OwaMailboxPolicy-Default", + "AdditionalStorageProvidersAvailable": True + } + """ + return self.execute("Get-OwaMailboxPolicy | ConvertTo-Json", json_parse=True) + def get_external_mail_config(self) -> dict: """ Get Exchange Online External Mail Configuration. @@ -467,20 +487,64 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) - def get_mailbox_policy(self) -> dict: - """ - Get Mailbox Policy. - Retrieves the current mailbox policy settings for Exchange Online. +# This function is used to install the required M365 PowerShell modules in Docker containers +def initialize_m365_powershell_modules(): + """ + Initialize required PowerShell modules. - Returns: - dict: Mailbox policy settings in JSON format. + Checks if the required PowerShell modules are installed and installs them if necessary. + This method ensures that all required modules for M365 operations are available. - Example: - >>> get_mailbox_policy() - { - "Id": "OwaMailboxPolicy-Default", - "AdditionalStorageProvidersAvailable": True - } - """ - return self.execute("Get-OwaMailboxPolicy | ConvertTo-Json", json_parse=True) + Returns: + bool: True if all modules were successfully initialized, False otherwise + """ + + REQUIRED_MODULES = [ + "ExchangeOnlineManagement", + "MicrosoftTeams", + ] + + pwsh = PowerShellSession() + try: + for module in REQUIRED_MODULES: + try: + # Check if module is already installed + result = pwsh.execute( + f"Get-Module -ListAvailable -Name {module}", timeout=5 + ) + + # Install module if not installed + if not result: + install_result = pwsh.execute( + f'Install-Module -Name "{module}" -Force -AllowClobber -Scope CurrentUser', + timeout=30, + ) + if install_result: + logger.warning( + f"Unexpected output while installing module {module}: {install_result}" + ) + else: + logger.info(f"Successfully installed module {module}") + + # Import module + pwsh.execute(f'Import-Module -Name "{module}" -Force', timeout=1) + + except Exception as error: + logger.error(f"Failed to initialize module {module}: {str(error)}") + return False + + return True + finally: + pwsh.close() + + +def main(): + if initialize_m365_powershell_modules(): + logger.info("M365 PowerShell modules initialized successfully") + else: + logger.error("Failed to initialize M365 PowerShell modules") + + +if __name__ == "__main__": + main() diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py index 4898b5c311..81b359728c 100644 --- a/prowler/providers/m365/m365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -53,7 +53,10 @@ from prowler.providers.m365.exceptions.exceptions import ( M365TenantIdAndClientSecretNotBelongingToClientIdError, ) from prowler.providers.m365.lib.mutelist.mutelist import M365Mutelist -from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell +from prowler.providers.m365.lib.powershell.m365_powershell import ( + M365PowerShell, + initialize_m365_powershell_modules, +) from prowler.providers.m365.lib.regions.regions import get_regions_config from prowler.providers.m365.models import ( M365Credentials, @@ -115,6 +118,7 @@ class M365Provider(Provider): client_secret: str = None, user: str = None, encrypted_password: str = None, + init_modules: bool = False, region: str = "M365Global", config_content: dict = None, config_path: str = None, @@ -202,6 +206,7 @@ class M365Provider(Provider): env_auth=env_auth, m365_credentials=m365_credentials, provider_id=self.identity.tenant_domain, + init_modules=init_modules, ) # Audit Config @@ -373,7 +378,10 @@ class M365Provider(Provider): @staticmethod def setup_powershell( - env_auth: bool = False, m365_credentials: dict = {}, provider_id: str = None + env_auth: bool = False, + m365_credentials: dict = {}, + provider_id: str = None, + init_modules: bool = False, ) -> M365Credentials: """Gets the M365 credentials. @@ -423,6 +431,8 @@ class M365Provider(Provider): test_session = M365PowerShell(credentials) try: if test_session.test_credentials(credentials): + if init_modules: + initialize_m365_powershell_modules() return credentials raise M365EnvironmentUserCredentialsError( file=os.path.basename(__file__), diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py index 72f5e72810..66094aa581 100644 --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -1,7 +1,8 @@ -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock, call, patch import pytest +from prowler.lib.powershell.powershell import PowerShellSession from prowler.providers.m365.exceptions.exceptions import ( M365UserNotBelongingToTenantError, ) @@ -265,6 +266,7 @@ class Testm365PowerShell: - Error in stderr - Timeout in stdout - Empty output + - Empty queue handling """ # Setup mock_process = MagicMock() @@ -308,6 +310,89 @@ class Testm365PowerShell: result = session.read_output() assert result == "" + # Test 5: Empty queue handling + mock_process.stdout.readline.side_effect = [] # No output at all + mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n" + result = session.read_output(timeout=0.1, default="empty_queue") + assert result == "empty_queue" + + # Test 6: Empty error queue handling + mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"] + mock_process.stderr.readline.side_effect = [] # No error output + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.read_output() + assert result == "test output" + mock_error.assert_not_called() + + # Test 7: Both queues empty + mock_process.stdout.readline.side_effect = [] # No output + mock_process.stderr.readline.side_effect = [] # No error output + result = session.read_output(timeout=0.1, default="both_empty") + assert result == "both_empty" + + session.close() + + @patch("subprocess.Popen") + def test_read_output_queue_empty(self, mock_popen): + """Test read_output when both queues are empty""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + # Mock process to return empty queues + mock_process.stdout.readline.side_effect = [] # No output + mock_process.stderr.readline.side_effect = [] # No error output + + # Test with default value + result = session.read_output(timeout=0.1, default="empty_queue") + assert result == "empty_queue" + + # Test without default value + result = session.read_output(timeout=0.1) + assert result == "" + + session.close() + + @patch("subprocess.Popen") + def test_read_output_error_queue_empty(self, mock_popen): + """Test read_output when error queue is empty but stdout has content""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + # Mock process to return content in stdout but empty stderr + mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"] + mock_process.stderr.readline.side_effect = [] # No error output + + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.read_output() + assert result == "test output" + mock_error.assert_not_called() + + session.close() + + @patch("subprocess.Popen") + def test_read_output_result_queue_empty(self, mock_popen): + """Test read_output when result queue is empty but stderr has content""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + credentials = M365Credentials(user="test@example.com", passwd="test_password") + session = M365PowerShell(credentials) + + # Mock process to return empty stdout but content in stderr + mock_process.stdout.readline.side_effect = [] # No output + mock_process.stderr.readline.side_effect = [ + "Error message\n", + f"Write-Error: {session.END}\n", + ] + + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.read_output(timeout=0.1, default="default") + assert result == "default" + mock_error.assert_called_once_with("PowerShell error output: Error message") + session.close() @patch("subprocess.Popen") @@ -346,3 +431,149 @@ class Testm365PowerShell: mock_process.stdin.flush.assert_called_once() mock_process.terminate.assert_called_once() + + @patch("subprocess.Popen") + def test_initialize_m365_powershell_modules_success(self, mock_popen): + """Test initialize_m365_powershell_modules when all modules are successfully initialized""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + + # Mock the execute method to simulate successful module installation + def mock_execute(command, *args, **kwargs): + if "Get-Module" in command: + return None # Module not installed + elif "Install-Module" in command: + return None # Installation successful + elif "Import-Module" in command: + return None # Import successful + return None + + with ( + patch.object( + PowerShellSession, "execute", side_effect=mock_execute + ) as mock_execute_obj, + patch("prowler.lib.logger.logger.info") as mock_info, + ): + from prowler.providers.m365.lib.powershell.m365_powershell import ( + initialize_m365_powershell_modules, + ) + + result = initialize_m365_powershell_modules() + + # Verify successful initialization + assert result is True + # Verify that execute was called for each module + assert mock_execute_obj.call_count == 6 # 2 modules * 3 commands each + # Verify success messages were logged + mock_info.assert_any_call( + "Successfully installed module ExchangeOnlineManagement" + ) + mock_info.assert_any_call("Successfully installed module MicrosoftTeams") + + @patch("subprocess.Popen") + def test_initialize_m365_powershell_modules_failure(self, mock_popen): + """Test initialize_m365_powershell_modules when module initialization fails""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + + # Mock the execute method to simulate installation failure + def mock_execute(command, *args, **kwargs): + if "Get-Module" in command: + return None # Module not installed + elif "Install-Module" in command: + raise Exception("Installation failed") + return None + + with ( + patch.object( + PowerShellSession, "execute", side_effect=mock_execute + ) as mock_execute_obj, + patch("prowler.lib.logger.logger.error") as mock_error, + ): + from prowler.providers.m365.lib.powershell.m365_powershell import ( + initialize_m365_powershell_modules, + ) + + result = initialize_m365_powershell_modules() + + # Verify failed initialization + assert result is False + # Verify that execute was called at least twice + assert mock_execute_obj.call_count >= 2 + # Verify error was logged + mock_error.assert_called_with( + "Failed to initialize module ExchangeOnlineManagement: Installation failed" + ) + + @patch("subprocess.Popen") + def test_main_success(self, mock_popen): + """Test main() function when module initialization is successful""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + + # Mock the execute method to simulate successful module installation + def mock_execute(command, *args, **kwargs): + if "Get-Module" in command: + return None # Module not installed + elif "Install-Module" in command: + return None # Installation successful + elif "Import-Module" in command: + return None # Import successful + return None + + with ( + patch.object(PowerShellSession, "execute", side_effect=mock_execute), + patch("prowler.lib.logger.logger.info") as mock_info, + patch("prowler.lib.logger.logger.error") as mock_error, + ): + from prowler.providers.m365.lib.powershell.m365_powershell import main + + main() + + # Verify all info messages were logged in the correct order + assert mock_info.call_count == 3 + mock_info.assert_has_calls( + [ + call("Successfully installed module ExchangeOnlineManagement"), + call("Successfully installed module MicrosoftTeams"), + call("M365 PowerShell modules initialized successfully"), + ] + ) + # Verify no error was logged + mock_error.assert_not_called() + + @patch("subprocess.Popen") + def test_main_failure(self, mock_popen): + """Test main() function when module initialization fails""" + mock_process = MagicMock() + mock_popen.return_value = mock_process + + # Mock the execute method to simulate installation failure + def mock_execute(command, *args, **kwargs): + if "Get-Module" in command: + return None # Module not installed + elif "Install-Module" in command: + raise Exception("Installation failed") + return None + + with ( + patch.object(PowerShellSession, "execute", side_effect=mock_execute), + patch("prowler.lib.logger.logger.info") as mock_info, + patch("prowler.lib.logger.logger.error") as mock_error, + ): + from prowler.providers.m365.lib.powershell.m365_powershell import main + + main() + + # Verify all error messages were logged in the correct order + assert mock_error.call_count == 2 + mock_error.assert_has_calls( + [ + call( + "Failed to initialize module ExchangeOnlineManagement: Installation failed" + ), + call("Failed to initialize M365 PowerShell modules"), + ] + ) + # Verify no info messages were logged + mock_info.assert_not_called() diff --git a/tests/providers/m365/m365_provider_test.py b/tests/providers/m365/m365_provider_test.py index 9fc991b60f..c891ab2d45 100644 --- a/tests/providers/m365/m365_provider_test.py +++ b/tests/providers/m365/m365_provider_test.py @@ -449,9 +449,11 @@ class TestM365Provider: "client_secret": "test_client_secret", } - with patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", - return_value=True, + with ( + patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", + return_value=True, + ), ): result = M365Provider.setup_powershell( env_auth=False, @@ -622,3 +624,87 @@ class TestM365Provider: f"Provider ID {provider_id} does not match Application tenant domain {user_domain}" in str(exception.value) ) + + def test_provider_init_modules_false(self): + """Test that initialize_m365_powershell_modules is not called when init_modules is False""" + credentials_dict = { + "user": "test@example.com", + "encrypted_password": "test_password", + "client_id": "test_client_id", + "tenant_id": "test_tenant_id", + "client_secret": "test_client_secret", + } + + with ( + patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", + return_value=True, + ), + patch( + "prowler.providers.m365.m365_provider.initialize_m365_powershell_modules" + ) as mock_init_modules, + ): + M365Provider.setup_powershell( + env_auth=False, + m365_credentials=credentials_dict, + provider_id="test_provider_id", + init_modules=False, + ) + mock_init_modules.assert_not_called() + + def test_provider_init_modules_true(self): + """Test that initialize_m365_powershell_modules is called when init_modules is True""" + credentials_dict = { + "user": "test@example.com", + "encrypted_password": "test_password", + "client_id": "test_client_id", + "tenant_id": "test_tenant_id", + "client_secret": "test_client_secret", + } + + with ( + patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", + return_value=True, + ), + patch( + "prowler.providers.m365.m365_provider.initialize_m365_powershell_modules" + ) as mock_init_modules, + ): + M365Provider.setup_powershell( + env_auth=False, + m365_credentials=credentials_dict, + provider_id="test_provider_id", + init_modules=True, + ) + mock_init_modules.assert_called_once() + + def test_setup_powershell_init_modules_failure(self): + """Test that setup_powershell handles initialization failures correctly""" + credentials_dict = { + "user": "test@example.com", + "encrypted_password": "test_password", + "client_id": "test_client_id", + "tenant_id": "test_tenant_id", + "client_secret": "test_client_secret", + } + + with ( + patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials", + return_value=True, + ), + patch( + "prowler.providers.m365.m365_provider.initialize_m365_powershell_modules", + side_effect=Exception("Module initialization failed"), + ), + ): + with pytest.raises(Exception) as exc_info: + M365Provider.setup_powershell( + env_auth=False, + m365_credentials=credentials_dict, + provider_id="test_provider_id", + init_modules=True, + ) + + assert str(exc_info.value) == "Module initialization failed" From c289ddacf2f1583b1b535fa0263f5c8607741946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?= Date: Wed, 30 Apr 2025 17:09:47 +0200 Subject: [PATCH 237/359] feat: add m365 to API (#7563) Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .pre-commit-config.yaml | 2 +- api/.pre-commit-config.yaml | 2 +- api/CHANGELOG.md | 8 + api/Dockerfile | 2 +- api/poetry.lock | 1877 +++++++++-------- api/pyproject.toml | 3 +- .../api/migrations/0017_m365_provider.py | 32 + api/src/backend/api/models.py | 10 + api/src/backend/api/specs/v1.yaml | 154 +- api/src/backend/api/tests/test_utils.py | 6 + api/src/backend/api/utils.py | 15 +- .../api/v1/serializer_utils/providers.py | 172 ++ api/src/backend/api/v1/serializers.py | 149 +- api/src/backend/api/v1/views.py | 2 +- poetry.lock | 1859 ++++++++-------- prowler/lib/powershell/powershell.py | 3 +- prowler/providers/m365/m365_provider.py | 12 +- pyproject.toml | 1 + 19 files changed, 2351 insertions(+), 1960 deletions(-) create mode 100644 api/src/backend/api/migrations/0017_m365_provider.py create mode 100644 api/src/backend/api/v1/serializer_utils/providers.py diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 1d4733d10a..49df46c8e5 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -145,7 +145,7 @@ jobs: working-directory: ./api if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' run: | - poetry run safety check --ignore 70612,66963 + poetry run safety check --ignore 70612,66963,74429 - name: Vulture working-directory: ./api diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a5d011e23d..0382dd901d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -115,7 +115,7 @@ repos: - id: safety name: safety description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities" - entry: bash -c 'safety check --ignore 70612,66963' + entry: bash -c 'safety check --ignore 70612,66963,74429' language: system - id: vulture diff --git a/api/.pre-commit-config.yaml b/api/.pre-commit-config.yaml index 6859567eb5..1cd04529c3 100644 --- a/api/.pre-commit-config.yaml +++ b/api/.pre-commit-config.yaml @@ -80,7 +80,7 @@ repos: - id: safety name: safety description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities" - entry: bash -c 'poetry run safety check --ignore 70612,66963' + entry: bash -c 'poetry run safety check --ignore 70612,66963,74429' language: system - id: vulture diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 44879c662a..84aedf43f7 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to the **Prowler API** are documented in this file. +## [v1.7.0] (UNRELEASED) + +### Added + +- Added M365 as a new provider [(#7563)](https://github.com/prowler-cloud/prowler/pull/7563). + +--- + ## [v1.6.0] (Prowler v5.5.0) ### Added diff --git a/api/Dockerfile b/api/Dockerfile index cf0fb37556..8291b14295 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -37,7 +37,7 @@ COPY pyproject.toml ./ RUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir poetry -COPY src/backend/ ./backend/ +COPY src/backend/ ./backend/ ENV PATH="/home/prowler/.local/bin:$PATH" diff --git a/api/poetry.lock b/api/poetry.lock index 0e9af82b8c..975d527172 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -14,105 +14,105 @@ files = [ [[package]] name = "aiohappyeyeballs" -version = "2.4.6" +version = "2.6.1" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1"}, - {file = "aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0"}, + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, ] [[package]] name = "aiohttp" -version = "3.11.12" +version = "3.11.18" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff"}, - {file = "aiohttp-3.11.12-cp310-cp310-win32.whl", hash = "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d"}, - {file = "aiohttp-3.11.12-cp310-cp310-win_amd64.whl", hash = "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b"}, - {file = "aiohttp-3.11.12-cp311-cp311-win32.whl", hash = "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16"}, - {file = "aiohttp-3.11.12-cp311-cp311-win_amd64.whl", hash = "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9"}, - {file = "aiohttp-3.11.12-cp312-cp312-win32.whl", hash = "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a"}, - {file = "aiohttp-3.11.12-cp312-cp312-win_amd64.whl", hash = "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce"}, - {file = "aiohttp-3.11.12-cp313-cp313-win32.whl", hash = "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f"}, - {file = "aiohttp-3.11.12-cp313-cp313-win_amd64.whl", hash = "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c3623053b85b4296cd3925eeb725e386644fd5bc67250b3bb08b0f144803e7b"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67453e603cea8e85ed566b2700efa1f6916aefbc0c9fcb2e86aaffc08ec38e78"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6130459189e61baac5a88c10019b21e1f0c6d00ebc770e9ce269475650ff7f73"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9060addfa4ff753b09392efe41e6af06ea5dd257829199747b9f15bfad819460"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34245498eeb9ae54c687a07ad7f160053911b5745e186afe2d0c0f2898a1ab8a"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dc0fba9a74b471c45ca1a3cb6e6913ebfae416678d90529d188886278e7f3f6"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a478aa11b328983c4444dacb947d4513cb371cd323f3845e53caeda6be5589d5"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c160a04283c8c6f55b5bf6d4cad59bb9c5b9c9cd08903841b25f1f7109ef1259"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:edb69b9589324bdc40961cdf0657815df674f1743a8d5ad9ab56a99e4833cfdd"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ee84c2a22a809c4f868153b178fe59e71423e1f3d6a8cd416134bb231fbf6d3"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bf4480a5438f80e0f1539e15a7eb8b5f97a26fe087e9828e2c0ec2be119a9f72"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b2732ef3bafc759f653a98881b5b9cdef0716d98f013d376ee8dfd7285abf1"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f752e80606b132140883bb262a457c475d219d7163d996dc9072434ffb0784c4"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab3247d58b393bda5b1c8f31c9edece7162fc13265334217785518dd770792b8"}, - {file = "aiohttp-3.11.12-cp39-cp39-win32.whl", hash = "sha256:0d5176f310a7fe6f65608213cc74f4228e4f4ce9fd10bcb2bb6da8fc66991462"}, - {file = "aiohttp-3.11.12-cp39-cp39-win_amd64.whl", hash = "sha256:74bd573dde27e58c760d9ca8615c41a57e719bff315c9adb6f2a4281a28e8798"}, - {file = "aiohttp-3.11.12.tar.gz", hash = "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96264854fedbea933a9ca4b7e0c745728f01380691687b7365d18d9e977179c4"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9602044ff047043430452bc3a2089743fa85da829e6fc9ee0025351d66c332b6"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5691dc38750fcb96a33ceef89642f139aa315c8a193bbd42a0c33476fd4a1609"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554c918ec43f8480b47a5ca758e10e793bd7410b83701676a4782672d670da55"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a4076a2b3ba5b004b8cffca6afe18a3b2c5c9ef679b4d1e9859cf76295f8d4f"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:767a97e6900edd11c762be96d82d13a1d7c4fc4b329f054e88b57cdc21fded94"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ddc9337a0fb0e727785ad4f41163cc314376e82b31846d3835673786420ef1"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f414f37b244f2a97e79b98d48c5ff0789a0b4b4609b17d64fa81771ad780e415"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fdb239f47328581e2ec7744ab5911f97afb10752332a6dd3d98e14e429e1a9e7"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2c50bad73ed629cc326cc0f75aed8ecfb013f88c5af116f33df556ed47143eb"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a8d8f20c39d3fa84d1c28cdb97f3111387e48209e224408e75f29c6f8e0861d"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:106032eaf9e62fd6bc6578c8b9e6dc4f5ed9a5c1c7fb2231010a1b4304393421"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b491e42183e8fcc9901d8dcd8ae644ff785590f1727f76ca86e731c61bfe6643"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad8c745ff9460a16b710e58e06a9dec11ebc0d8f4dd82091cefb579844d69868"}, + {file = "aiohttp-3.11.18-cp310-cp310-win32.whl", hash = "sha256:8e57da93e24303a883146510a434f0faf2f1e7e659f3041abc4e3fb3f6702a9f"}, + {file = "aiohttp-3.11.18-cp310-cp310-win_amd64.whl", hash = "sha256:cc93a4121d87d9f12739fc8fab0a95f78444e571ed63e40bfc78cd5abe700ac9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:427fdc56ccb6901ff8088544bde47084845ea81591deb16f957897f0f0ba1be9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c828b6d23b984255b85b9b04a5b963a74278b7356a7de84fda5e3b76866597b"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c2eaa145bb36b33af1ff2860820ba0589e165be4ab63a49aebfd0981c173b66"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d518ce32179f7e2096bf4e3e8438cf445f05fedd597f252de9f54c728574756"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0700055a6e05c2f4711011a44364020d7a10fbbcd02fbf3e30e8f7e7fddc8717"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bd1cde83e4684324e6ee19adfc25fd649d04078179890be7b29f76b501de8e4"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73b8870fe1c9a201b8c0d12c94fe781b918664766728783241a79e0468427e4f"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25557982dd36b9e32c0a3357f30804e80790ec2c4d20ac6bcc598533e04c6361"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e889c9df381a2433802991288a61e5a19ceb4f61bd14f5c9fa165655dcb1fd1"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9ea345fda05bae217b6cce2acf3682ce3b13d0d16dd47d0de7080e5e21362421"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f26545b9940c4b46f0a9388fd04ee3ad7064c4017b5a334dd450f616396590e"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3a621d85e85dccabd700294494d7179ed1590b6d07a35709bb9bd608c7f5dd1d"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c23fd8d08eb9c2af3faeedc8c56e134acdaf36e2117ee059d7defa655130e5f"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9e6b0e519067caa4fd7fb72e3e8002d16a68e84e62e7291092a5433763dc0dd"}, + {file = "aiohttp-3.11.18-cp311-cp311-win32.whl", hash = "sha256:122f3e739f6607e5e4c6a2f8562a6f476192a682a52bda8b4c6d4254e1138f4d"}, + {file = "aiohttp-3.11.18-cp311-cp311-win_amd64.whl", hash = "sha256:e6f3c0a3a1e73e88af384b2e8a0b9f4fb73245afd47589df2afcab6b638fa0e6"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63d71eceb9cad35d47d71f78edac41fcd01ff10cacaa64e473d1aec13fa02df2"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d1929da615840969929e8878d7951b31afe0bac883d84418f92e5755d7b49508"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0aebeb2392f19b184e3fdd9e651b0e39cd0f195cdb93328bd124a1d455cd0e"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3849ead845e8444f7331c284132ab314b4dac43bfae1e3cf350906d4fff4620f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e8452ad6b2863709f8b3d615955aa0807bc093c34b8e25b3b52097fe421cb7f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b8d2b42073611c860a37f718b3d61ae8b4c2b124b2e776e2c10619d920350ec"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fbf91f6a0ac317c0a07eb328a1384941872f6761f2e6f7208b63c4cc0a7ff6"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ff5625413fec55216da5eaa011cf6b0a2ed67a565914a212a51aa3755b0009"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f33a92a2fde08e8c6b0c61815521324fc1612f397abf96eed86b8e31618fdb4"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:11d5391946605f445ddafda5eab11caf310f90cdda1fd99865564e3164f5cff9"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3cc314245deb311364884e44242e00c18b5896e4fe6d5f942e7ad7e4cb640adb"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f421843b0f70740772228b9e8093289924359d306530bcd3926f39acbe1adda"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e220e7562467dc8d589e31c1acd13438d82c03d7f385c9cd41a3f6d1d15807c1"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab2ef72f8605046115bc9aa8e9d14fd49086d405855f40b79ed9e5c1f9f4faea"}, + {file = "aiohttp-3.11.18-cp312-cp312-win32.whl", hash = "sha256:12a62691eb5aac58d65200c7ae94d73e8a65c331c3a86a2e9670927e94339ee8"}, + {file = "aiohttp-3.11.18-cp312-cp312-win_amd64.whl", hash = "sha256:364329f319c499128fd5cd2d1c31c44f234c58f9b96cc57f743d16ec4f3238c8"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:474215ec618974054cf5dc465497ae9708543cbfc312c65212325d4212525811"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ced70adf03920d4e67c373fd692123e34d3ac81dfa1c27e45904a628567d804"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d9f6c0152f8d71361905aaf9ed979259537981f47ad099c8b3d81e0319814bd"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a35197013ed929c0aed5c9096de1fc5a9d336914d73ab3f9df14741668c0616c"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:540b8a1f3a424f1af63e0af2d2853a759242a1769f9f1ab053996a392bd70118"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9e6710ebebfce2ba21cee6d91e7452d1125100f41b906fb5af3da8c78b764c1"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8af2ef3b4b652ff109f98087242e2ab974b2b2b496304063585e3d78de0b000"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28c3f975e5ae3dbcbe95b7e3dcd30e51da561a0a0f2cfbcdea30fc1308d72137"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c28875e316c7b4c3e745172d882d8a5c835b11018e33432d281211af35794a93"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:13cd38515568ae230e1ef6919e2e33da5d0f46862943fcda74e7e915096815f3"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0e2a92101efb9f4c2942252c69c63ddb26d20f46f540c239ccfa5af865197bb8"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e6d3e32b8753c8d45ac550b11a1090dd66d110d4ef805ffe60fa61495360b3b2"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ea4cf2488156e0f281f93cc2fd365025efcba3e2d217cbe3df2840f8c73db261"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d4df95ad522c53f2b9ebc07f12ccd2cb15550941e11a5bbc5ddca2ca56316d7"}, + {file = "aiohttp-3.11.18-cp313-cp313-win32.whl", hash = "sha256:cdd1bbaf1e61f0d94aced116d6e95fe25942f7a5f42382195fd9501089db5d78"}, + {file = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl", hash = "sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:469ac32375d9a716da49817cd26f1916ec787fc82b151c1c832f58420e6d3533"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cec21dd68924179258ae14af9f5418c1ebdbba60b98c667815891293902e5e0"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b426495fb9140e75719b3ae70a5e8dd3a79def0ae3c6c27e012fc59f16544a4a"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2f41203e2808616292db5d7170cccf0c9f9c982d02544443c7eb0296e8b0c7"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc0ae0a5e9939e423e065a3e5b00b24b8379f1db46046d7ab71753dfc7dd0e1"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7cdd3f7d1df43200e1c80f1aed86bb36033bf65e3c7cf46a2b97a253ef8798"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5199be2a2f01ffdfa8c3a6f5981205242986b9e63eb8ae03fd18f736e4840721"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ccec9e72660b10f8e283e91aa0295975c7bd85c204011d9f5eb69310555cf30"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1596ebf17e42e293cbacc7a24c3e0dc0f8f755b40aff0402cb74c1ff6baec1d3"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eab7b040a8a873020113ba814b7db7fa935235e4cbaf8f3da17671baa1024863"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5d61df4a05476ff891cff0030329fee4088d40e4dc9b013fac01bc3c745542c2"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:46533e6792e1410f9801d09fd40cbbff3f3518d1b501d6c3c5b218f427f6ff08"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c1b90407ced992331dd6d4f1355819ea1c274cc1ee4d5b7046c6761f9ec11829"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a2fd04ae4971b914e54fe459dd7edbbd3f2ba875d69e057d5e3c8e8cac094935"}, + {file = "aiohttp-3.11.18-cp39-cp39-win32.whl", hash = "sha256:b2f317d1678002eee6fe85670039fb34a757972284614638f82b903a03feacdc"}, + {file = "aiohttp-3.11.18-cp39-cp39-win_amd64.whl", hash = "sha256:5e7007b8d1d09bce37b54111f593d173691c530b80f27c6493b928dabed9e6ef"}, + {file = "aiohttp-3.11.18.tar.gz", hash = "sha256:ae856e1138612b7e412db63b7708735cff4d38d0399f6a5435d3dac2669f558a"}, ] [package.dependencies] @@ -175,14 +175,14 @@ vine = ">=5.0.0,<6.0.0" [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, + {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, ] [package.dependencies] @@ -191,8 +191,8 @@ sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] +doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -237,34 +237,34 @@ files = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, - {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "authlib" -version = "1.4.1" +version = "1.5.2" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "Authlib-1.4.1-py2.py3-none-any.whl", hash = "sha256:edc29c3f6a3e72cd9e9f45fff67fc663a2c364022eb0371c003f22d5405915c1"}, - {file = "authlib-1.4.1.tar.gz", hash = "sha256:30ead9ea4993cdbab821dc6e01e818362f92da290c04c7f6a1940f86507a790d"}, + {file = "authlib-1.5.2-py2.py3-none-any.whl", hash = "sha256:8804dd4402ac5e4a0435ac49e0b6e19e395357cfa632a3f624dcb4f6df13b4b1"}, + {file = "authlib-1.5.2.tar.gz", hash = "sha256:fe85ec7e50c5f86f1e2603518bb3b4f632985eb4a355e52256530790e326c512"}, ] [package.dependencies] @@ -311,14 +311,14 @@ files = [ [[package]] name = "azure-core" -version = "1.32.0" +version = "1.33.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, - {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, + {file = "azure_core-1.33.0-py3-none-any.whl", hash = "sha256:9b5b6d0223a1d38c37500e6971118c1e0f13f54951e6893968b38910bc9cda8f"}, + {file = "azure_core-1.33.0.tar.gz", hash = "sha256:f367aa07b5e3005fec2c1e184b882b0b039910733907d001c20fb08ebb8c0eb9"}, ] [package.dependencies] @@ -328,17 +328,18 @@ typing-extensions = ">=4.6.0" [package.extras] aio = ["aiohttp (>=3.0)"] +tracing = ["opentelemetry-api (>=1.26,<2.0)"] [[package]] name = "azure-identity" -version = "1.19.0" +version = "1.21.0" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81"}, - {file = "azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83"}, + {file = "azure_identity-1.21.0-py3-none-any.whl", hash = "sha256:258ea6325537352440f71b35c3dffe9d240eae4a5126c1b7ce5efd5766bd9fd9"}, + {file = "azure_identity-1.21.0.tar.gz", hash = "sha256:ea22ce6e6b0f429bc1b8d9212d5b9f9877bd4c82f1724bfa910760612c07a9a6"}, ] [package.dependencies] @@ -368,20 +369,21 @@ typing-extensions = ">=4.0.1" [[package]] name = "azure-mgmt-applicationinsights" -version = "4.0.0" +version = "4.1.0" description = "Microsoft Azure Application Insights Management Client Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-applicationinsights-4.0.0.zip", hash = "sha256:50c3db05573e0cc2d56314a0556fb346ef05ec489ac000f4d720d92c6b647e06"}, - {file = "azure_mgmt_applicationinsights-4.0.0-py3-none-any.whl", hash = "sha256:2b1ffd9a0114974455795c73a3a5d17c849e32b961d707d2db393b99254b576f"}, + {file = "azure_mgmt_applicationinsights-4.1.0-py3-none-any.whl", hash = "sha256:9e71f29b01e505a773501451d12fd6a10482cf4b13e9ac2bff72f5380496d979"}, + {file = "azure_mgmt_applicationinsights-4.1.0.tar.gz", hash = "sha256:15531390f12ce3d767cd3f1949af36aa39077c145c952fec4d80303c86ec7b6c"}, ] [package.dependencies] -azure-common = ">=1.1,<2.0" -azure-mgmt-core = ">=1.3.2,<2.0.0" -isodate = ">=0.6.1,<1.0.0" +azure-common = ">=1.1" +azure-mgmt-core = ">=1.3.2" +isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-authorization" @@ -420,31 +422,32 @@ typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-containerregistry" -version = "10.3.0" +version = "12.0.0" description = "Microsoft Azure Container Registry Client Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-containerregistry-10.3.0.tar.gz", hash = "sha256:ae21651855dfb19c42d91d6b3a965c6c611e23f8bc4bf7138835e652d2f918e3"}, - {file = "azure_mgmt_containerregistry-10.3.0-py3-none-any.whl", hash = "sha256:851e1c57f9bc4a3589c6b21fb627c11fd6cbb57a0388b7dfccd530ba3160805f"}, + {file = "azure_mgmt_containerregistry-12.0.0-py3-none-any.whl", hash = "sha256:464abd4d3d9ecc0456ed8f63a6b9b93afc2e3e194f2d34f26a758afb67ad3b5c"}, + {file = "azure_mgmt_containerregistry-12.0.0.tar.gz", hash = "sha256:f19f8faa7881deaf2b5015c0eb050a92e2380cd9d18dee33cdb5f27d44a06c03"}, ] [package.dependencies] -azure-common = ">=1.1,<2.0" -azure-mgmt-core = ">=1.3.2,<2.0.0" -isodate = ">=0.6.1,<1.0.0" +azure-common = ">=1.1" +azure-mgmt-core = ">=1.3.2" +isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-containerservice" -version = "34.0.0" +version = "34.1.0" description = "Microsoft Azure Container Service Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_mgmt_containerservice-34.0.0-py3-none-any.whl", hash = "sha256:34be8172241e3c2c444682407970a938f60e3b2bd06304eaae0a1ba641f2262d"}, - {file = "azure_mgmt_containerservice-34.0.0.tar.gz", hash = "sha256:822d07828b746a5ea5408a8b3770f41dc424d6c4c28de53c29611b62bef8aea3"}, + {file = "azure_mgmt_containerservice-34.1.0-py3-none-any.whl", hash = "sha256:1faa1714e0100c6ee4cfb8d2eadb1c270b548a84b0070c74e9fe646056a5cb12"}, + {file = "azure_mgmt_containerservice-34.1.0.tar.gz", hash = "sha256:637a6cf8f06636c016ad151d76f9c7ba75bd05d4334b3dd7837eb8b517f30dbe"}, ] [package.dependencies] @@ -558,14 +561,14 @@ msrest = ">=0.6.21" [[package]] name = "azure-mgmt-resource" -version = "23.2.0" +version = "23.3.0" description = "Microsoft Azure Resource Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_mgmt_resource-23.2.0-py3-none-any.whl", hash = "sha256:7af2bca928ecd58e57ea7f7731d245f45e9d927036d82f1d30b96baa0c26b569"}, - {file = "azure_mgmt_resource-23.2.0.tar.gz", hash = "sha256:747b750df7af23ab30e53d3f36247ab0c16de1e267d666b1a5077c39a4292529"}, + {file = "azure_mgmt_resource-23.3.0-py3-none-any.whl", hash = "sha256:ab216ee28e29db6654b989746e0c85a1181f66653929d2cb6e48fba66d9af323"}, + {file = "azure_mgmt_resource-23.3.0.tar.gz", hash = "sha256:fc4f1fd8b6aad23f8af4ed1f913df5f5c92df117449dc354fea6802a2829fea4"}, ] [package.dependencies] @@ -627,20 +630,21 @@ msrest = ">=0.6.21" [[package]] name = "azure-mgmt-storage" -version = "21.2.1" +version = "22.1.1" description = "Microsoft Azure Storage Management Client Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure-mgmt-storage-21.2.1.tar.gz", hash = "sha256:503a7ff9c31254092b0656445f5728bfdfda2d09d46a82e97019eaa9a1ecec64"}, - {file = "azure_mgmt_storage-21.2.1-py3-none-any.whl", hash = "sha256:f97df1fa39cde9dbacf2cd96c9cba1fc196932185e24853e276f74b18a0bd031"}, + {file = "azure_mgmt_storage-22.1.1-py3-none-any.whl", hash = "sha256:a4a4064918dcfa4f1cbebada5bf064935d66f2a3647a2f46a1f1c9348736f5d9"}, + {file = "azure_mgmt_storage-22.1.1.tar.gz", hash = "sha256:25aaa5ae8c40c30e2f91f8aae6f52906b0557e947d5c1b9817d4ff9decc11340"}, ] [package.dependencies] azure-common = ">=1.1" azure-mgmt-core = ">=1.3.2" isodate = ">=0.6.1" +typing-extensions = ">=4.6.0" [[package]] name = "azure-mgmt-subscription" @@ -789,14 +793,14 @@ crt = ["awscrt (==0.22.0)"] [[package]] name = "cachetools" -version = "5.5.1" +version = "5.5.2" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, - {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, + {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, + {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, ] [[package]] @@ -1356,38 +1360,38 @@ files = [ [[package]] name = "debugpy" -version = "1.8.12" +version = "1.8.14" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a"}, - {file = "debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45"}, - {file = "debugpy-1.8.12-cp310-cp310-win32.whl", hash = "sha256:b202f591204023b3ce62ff9a47baa555dc00bb092219abf5caf0e3718ac20e7c"}, - {file = "debugpy-1.8.12-cp310-cp310-win_amd64.whl", hash = "sha256:9649eced17a98ce816756ce50433b2dd85dfa7bc92ceb60579d68c053f98dff9"}, - {file = "debugpy-1.8.12-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:36f4829839ef0afdfdd208bb54f4c3d0eea86106d719811681a8627ae2e53dd5"}, - {file = "debugpy-1.8.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28ed481d530e3138553be60991d2d61103ce6da254e51547b79549675f539b7"}, - {file = "debugpy-1.8.12-cp311-cp311-win32.whl", hash = "sha256:4ad9a94d8f5c9b954e0e3b137cc64ef3f579d0df3c3698fe9c3734ee397e4abb"}, - {file = "debugpy-1.8.12-cp311-cp311-win_amd64.whl", hash = "sha256:4703575b78dd697b294f8c65588dc86874ed787b7348c65da70cfc885efdf1e1"}, - {file = "debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498"}, - {file = "debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06"}, - {file = "debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d"}, - {file = "debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969"}, - {file = "debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f"}, - {file = "debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9"}, - {file = "debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180"}, - {file = "debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c"}, - {file = "debugpy-1.8.12-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:b0232cd42506d0c94f9328aaf0d1d0785f90f87ae72d9759df7e5051be039738"}, - {file = "debugpy-1.8.12-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9af40506a59450f1315168d47a970db1a65aaab5df3833ac389d2899a5d63b3f"}, - {file = "debugpy-1.8.12-cp38-cp38-win32.whl", hash = "sha256:5cc45235fefac57f52680902b7d197fb2f3650112379a6fa9aa1b1c1d3ed3f02"}, - {file = "debugpy-1.8.12-cp38-cp38-win_amd64.whl", hash = "sha256:557cc55b51ab2f3371e238804ffc8510b6ef087673303890f57a24195d096e61"}, - {file = "debugpy-1.8.12-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:b5c6c967d02fee30e157ab5227706f965d5c37679c687b1e7bbc5d9e7128bd41"}, - {file = "debugpy-1.8.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a77f422f31f170c4b7e9ca58eae2a6c8e04da54121900651dfa8e66c29901a"}, - {file = "debugpy-1.8.12-cp39-cp39-win32.whl", hash = "sha256:a4042edef80364239f5b7b5764e55fd3ffd40c32cf6753da9bda4ff0ac466018"}, - {file = "debugpy-1.8.12-cp39-cp39-win_amd64.whl", hash = "sha256:f30b03b0f27608a0b26c75f0bb8a880c752c0e0b01090551b9d87c7d783e2069"}, - {file = "debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6"}, - {file = "debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce"}, + {file = "debugpy-1.8.14-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:93fee753097e85623cab1c0e6a68c76308cd9f13ffdf44127e6fab4fbf024339"}, + {file = "debugpy-1.8.14-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d937d93ae4fa51cdc94d3e865f535f185d5f9748efb41d0d49e33bf3365bd79"}, + {file = "debugpy-1.8.14-cp310-cp310-win32.whl", hash = "sha256:c442f20577b38cc7a9aafecffe1094f78f07fb8423c3dddb384e6b8f49fd2987"}, + {file = "debugpy-1.8.14-cp310-cp310-win_amd64.whl", hash = "sha256:f117dedda6d969c5c9483e23f573b38f4e39412845c7bc487b6f2648df30fe84"}, + {file = "debugpy-1.8.14-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:1b2ac8c13b2645e0b1eaf30e816404990fbdb168e193322be8f545e8c01644a9"}, + {file = "debugpy-1.8.14-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf431c343a99384ac7eab2f763980724834f933a271e90496944195318c619e2"}, + {file = "debugpy-1.8.14-cp311-cp311-win32.whl", hash = "sha256:c99295c76161ad8d507b413cd33422d7c542889fbb73035889420ac1fad354f2"}, + {file = "debugpy-1.8.14-cp311-cp311-win_amd64.whl", hash = "sha256:7816acea4a46d7e4e50ad8d09d963a680ecc814ae31cdef3622eb05ccacf7b01"}, + {file = "debugpy-1.8.14-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:8899c17920d089cfa23e6005ad9f22582fd86f144b23acb9feeda59e84405b84"}, + {file = "debugpy-1.8.14-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6bb5c0dcf80ad5dbc7b7d6eac484e2af34bdacdf81df09b6a3e62792b722826"}, + {file = "debugpy-1.8.14-cp312-cp312-win32.whl", hash = "sha256:281d44d248a0e1791ad0eafdbbd2912ff0de9eec48022a5bfbc332957487ed3f"}, + {file = "debugpy-1.8.14-cp312-cp312-win_amd64.whl", hash = "sha256:5aa56ef8538893e4502a7d79047fe39b1dae08d9ae257074c6464a7b290b806f"}, + {file = "debugpy-1.8.14-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:329a15d0660ee09fec6786acdb6e0443d595f64f5d096fc3e3ccf09a4259033f"}, + {file = "debugpy-1.8.14-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f920c7f9af409d90f5fd26e313e119d908b0dd2952c2393cd3247a462331f15"}, + {file = "debugpy-1.8.14-cp313-cp313-win32.whl", hash = "sha256:3784ec6e8600c66cbdd4ca2726c72d8ca781e94bce2f396cc606d458146f8f4e"}, + {file = "debugpy-1.8.14-cp313-cp313-win_amd64.whl", hash = "sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e"}, + {file = "debugpy-1.8.14-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:d5582bcbe42917bc6bbe5c12db1bffdf21f6bfc28d4554b738bf08d50dc0c8c3"}, + {file = "debugpy-1.8.14-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5349b7c3735b766a281873fbe32ca9cca343d4cc11ba4a743f84cb854339ff35"}, + {file = "debugpy-1.8.14-cp38-cp38-win32.whl", hash = "sha256:7118d462fe9724c887d355eef395fae68bc764fd862cdca94e70dcb9ade8a23d"}, + {file = "debugpy-1.8.14-cp38-cp38-win_amd64.whl", hash = "sha256:d235e4fa78af2de4e5609073972700523e372cf5601742449970110d565ca28c"}, + {file = "debugpy-1.8.14-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:413512d35ff52c2fb0fd2d65e69f373ffd24f0ecb1fac514c04a668599c5ce7f"}, + {file = "debugpy-1.8.14-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c9156f7524a0d70b7a7e22b2e311d8ba76a15496fb00730e46dcdeedb9e1eea"}, + {file = "debugpy-1.8.14-cp39-cp39-win32.whl", hash = "sha256:b44985f97cc3dd9d52c42eb59ee9d7ee0c4e7ecd62bca704891f997de4cef23d"}, + {file = "debugpy-1.8.14-cp39-cp39-win_amd64.whl", hash = "sha256:b1528cfee6c1b1c698eb10b6b096c598738a8238822d218173d21c3086de8123"}, + {file = "debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20"}, + {file = "debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322"}, ] [[package]] @@ -1430,14 +1434,14 @@ word-list = ["pyahocorasick"] [[package]] name = "dill" -version = "0.3.9" +version = "0.4.0" description = "serialize all of Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, - {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, + {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, + {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, ] [package.extras] @@ -1511,39 +1515,39 @@ steam = ["python3-openid (>=3.0.8)"] [[package]] name = "django-celery-beat" -version = "2.7.0" +version = "2.8.0" description = "Database-backed Periodic Tasks." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "django_celery_beat-2.7.0-py3-none-any.whl", hash = "sha256:851c680d8fbf608ca5fecd5836622beea89fa017bc2b3f94a5b8c648c32d84b1"}, - {file = "django_celery_beat-2.7.0.tar.gz", hash = "sha256:8482034925e09b698c05ad61c36ed2a8dbc436724a3fe119215193a4ca6dc967"}, + {file = "django_celery_beat-2.8.0-py3-none-any.whl", hash = "sha256:f8fd2e1ffbfa8e570ab9439383b2cd15a6642b347662d0de79c62ba6f68d4b38"}, + {file = "django_celery_beat-2.8.0.tar.gz", hash = "sha256:955bfb3c4b8f1026a8d20144d0da39c941e1eb23acbaee9e12a7e7cc1f74959a"}, ] [package.dependencies] celery = ">=5.2.3,<6.0" cron-descriptor = ">=1.2.32" -Django = ">=2.2,<5.2" +Django = ">=2.2,<6.0" django-timezone-field = ">=5.0" python-crontab = ">=2.3.4" tzdata = "*" [[package]] name = "django-celery-results" -version = "2.5.1" +version = "2.6.0" description = "Celery result backends for Django." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_results-2.5.1-py3-none-any.whl", hash = "sha256:0da4cd5ecc049333e4524a23fcfc3460dfae91aa0a60f1fae4b6b2889c254e01"}, - {file = "django_celery_results-2.5.1.tar.gz", hash = "sha256:3ecb7147f773f34d0381bac6246337ce4cf88a2ea7b82774ed48e518b67bb8fd"}, + {file = "django_celery_results-2.6.0-py3-none-any.whl", hash = "sha256:b9ccdca2695b98c7cbbb8dea742311ba9a92773d71d7b4944a676e69a7df1c73"}, + {file = "django_celery_results-2.6.0.tar.gz", hash = "sha256:9abcd836ae6b61063779244d8887a88fe80bbfaba143df36d3cb07034671277c"}, ] [package.dependencies] celery = ">=5.2.7,<6.0" -Django = ">=3.2.18" +Django = ">=3.2.25" [[package]] name = "django-cors-headers" @@ -1702,26 +1706,26 @@ openapi = ["pyyaml (>=5.4)", "uritemplate (>=3.0.1)"] [[package]] name = "djangorestframework-simplejwt" -version = "5.4.0" +version = "5.5.0" description = "A minimal JSON Web Token authentication plugin for Django REST Framework" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "djangorestframework_simplejwt-5.4.0-py3-none-any.whl", hash = "sha256:7aec953db9ed4163430c16d086eecb0f028f814ce6bba62b06c25919261e9077"}, - {file = "djangorestframework_simplejwt-5.4.0.tar.gz", hash = "sha256:cccecce1a0e1a4a240fae80da73e5fc23055bababb8b67de88fa47cd36822320"}, + {file = "djangorestframework_simplejwt-5.5.0-py3-none-any.whl", hash = "sha256:4ef6b38af20cdde4a4a51d1fd8e063cbbabb7b45f149cc885d38d905c5a62edb"}, + {file = "djangorestframework_simplejwt-5.5.0.tar.gz", hash = "sha256:474a1b737067e6462b3609627a392d13a4da8a08b1f0574104ac6d7b1406f90e"}, ] [package.dependencies] django = ">=4.2" djangorestframework = ">=3.14" -pyjwt = ">=1.7.1,<3" +pyjwt = ">=1.7.1,<2.10.0" [package.extras] crypto = ["cryptography (>=3.3.1)"] -dev = ["Sphinx (>=1.6.5,<2)", "cryptography", "flake8", "freezegun", "ipython", "isort", "pep8", "pytest", "pytest-cov", "pytest-django", "pytest-watch", "pytest-xdist", "python-jose (==3.3.0)", "sphinx_rtd_theme (>=0.1.9)", "tox", "twine", "wheel"] +dev = ["Sphinx (>=1.6.5,<2)", "cryptography", "freezegun", "ipython", "pre-commit", "pytest", "pytest-cov", "pytest-django", "pytest-watch", "pytest-xdist", "python-jose (==3.3.0)", "pyupgrade", "ruff", "sphinx_rtd_theme (>=0.1.9)", "tox", "twine", "wheel", "yesqa"] doc = ["Sphinx (>=1.6.5,<2)", "sphinx_rtd_theme (>=0.1.9)"] -lint = ["flake8", "isort", "pep8"] +lint = ["pre-commit", "pyupgrade", "ruff", "yesqa"] python-jose = ["python-jose (==3.3.0)"] test = ["cryptography", "freezegun", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "tox"] @@ -1792,18 +1796,20 @@ poetry = ["poetry"] [[package]] name = "drf-extensions" -version = "0.7.1" +version = "0.8.0" description = "Extensions for Django REST Framework" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "drf-extensions-0.7.1.tar.gz", hash = "sha256:90abfc11a2221e8daf4cd54457e41ed38cd71134678de9622e806193db027db1"}, - {file = "drf_extensions-0.7.1-py2.py3-none-any.whl", hash = "sha256:007910437e64aa1d5ad6fc47266a4ac4280e31761e6458eb30fcac7494ac7d4e"}, + {file = "drf_extensions-0.8.0-py2.py3-none-any.whl", hash = "sha256:ab7bd854c9061c27ab55233b66d758001e5c2d81aaa9d117cbbe1c9ea49c77ab"}, + {file = "drf_extensions-0.8.0.tar.gz", hash = "sha256:c3f27bca74a2def53e8454a5c7b327595195df51e121743120b2f51ef5a52aaa"}, ] [package.dependencies] -djangorestframework = ">=3.9.3" +Django = ">=2.2,<6.0" +djangorestframework = ">=3.10.3" +packaging = ">=24.1" [[package]] name = "drf-nested-routers" @@ -1964,124 +1970,136 @@ python-dateutil = ">=2.7" [[package]] name = "frozenlist" -version = "1.5.0" +version = "1.6.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, - {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, - {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, - {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, - {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, - {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, - {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, - {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, - {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, - {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, - {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, - {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, - {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, - {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, - {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e6e558ea1e47fd6fa8ac9ccdad403e5dd5ecc6ed8dda94343056fa4277d5c65e"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4b3cd7334a4bbc0c472164f3744562cb72d05002cc6fcf58adb104630bbc352"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9799257237d0479736e2b4c01ff26b5c7f7694ac9692a426cb717f3dc02fff9b"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a7bb0fe1f7a70fb5c6f497dc32619db7d2cdd53164af30ade2f34673f8b1fc"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:36d2fc099229f1e4237f563b2a3e0ff7ccebc3999f729067ce4e64a97a7f2869"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f27a9f9a86dcf00708be82359db8de86b80d029814e6693259befe82bb58a106"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75ecee69073312951244f11b8627e3700ec2bfe07ed24e3a685a5979f0412d24"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2c7d5aa19714b1b01a0f515d078a629e445e667b9da869a3cd0e6fe7dec78bd"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69bbd454f0fb23b51cadc9bdba616c9678e4114b6f9fa372d462ff2ed9323ec8"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7daa508e75613809c7a57136dec4871a21bca3080b3a8fc347c50b187df4f00c"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:89ffdb799154fd4d7b85c56d5fa9d9ad48946619e0eb95755723fffa11022d75"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:920b6bd77d209931e4c263223381d63f76828bec574440f29eb497cf3394c249"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d3ceb265249fb401702fce3792e6b44c1166b9319737d21495d3611028d95769"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52021b528f1571f98a7d4258c58aa8d4b1a96d4f01d00d51f1089f2e0323cb02"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f2ca7810b809ed0f1917293050163c7654cefc57a49f337d5cd9de717b8fad3"}, + {file = "frozenlist-1.6.0-cp310-cp310-win32.whl", hash = "sha256:0e6f8653acb82e15e5443dba415fb62a8732b68fe09936bb6d388c725b57f812"}, + {file = "frozenlist-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a39819a5a3e84304cd286e3dc62a549fe60985415851b3337b6f5cc91907f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae8337990e7a45683548ffb2fee1af2f1ed08169284cd829cdd9a7fa7470530d"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c952f69dd524558694818a461855f35d36cc7f5c0adddce37e962c85d06eac0"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f5fef13136c4e2dee91bfb9a44e236fff78fc2cd9f838eddfc470c3d7d90afe"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:716bbba09611b4663ecbb7cd022f640759af8259e12a6ca939c0a6acd49eedba"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b8c4dc422c1a3ffc550b465090e53b0bf4839047f3e436a34172ac67c45d595"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b11534872256e1666116f6587a1592ef395a98b54476addb5e8d352925cb5d4a"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c6eceb88aaf7221f75be6ab498dc622a151f5f88d536661af3ffc486245a626"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62c828a5b195570eb4b37369fcbbd58e96c905768d53a44d13044355647838ff"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c6bd2c6399920c9622362ce95a7d74e7f9af9bfec05fff91b8ce4b9647845a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49ba23817781e22fcbd45fd9ff2b9b8cdb7b16a42a4851ab8025cae7b22e96d0"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:431ef6937ae0f853143e2ca67d6da76c083e8b1fe3df0e96f3802fd37626e606"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9d124b38b3c299ca68433597ee26b7819209cb8a3a9ea761dfe9db3a04bba584"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:118e97556306402e2b010da1ef21ea70cb6d6122e580da64c056b96f524fbd6a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb3b309f1d4086b5533cf7bbcf3f956f0ae6469664522f1bde4feed26fba60f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54dece0d21dce4fdb188a1ffc555926adf1d1c516e493c2914d7c370e454bc9e"}, + {file = "frozenlist-1.6.0-cp311-cp311-win32.whl", hash = "sha256:654e4ba1d0b2154ca2f096bed27461cf6160bc7f504a7f9a9ef447c293caf860"}, + {file = "frozenlist-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e911391bffdb806001002c1f860787542f45916c3baf764264a52765d5a5603"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770"}, + {file = "frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc"}, + {file = "frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d7fb014fe0fbfee3efd6a94fc635aeaa68e5e1720fe9e57357f2e2c6e1a647e"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01bcaa305a0fdad12745502bfd16a1c75b14558dabae226852f9159364573117"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b314faa3051a6d45da196a2c495e922f987dc848e967d8cfeaee8a0328b1cd4"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da62fecac21a3ee10463d153549d8db87549a5e77eefb8c91ac84bb42bb1e4e3"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1eb89bf3454e2132e046f9599fbcf0a4483ed43b40f545551a39316d0201cd1"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18689b40cb3936acd971f663ccb8e2589c45db5e2c5f07e0ec6207664029a9c"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e67ddb0749ed066b1a03fba812e2dcae791dd50e5da03be50b6a14d0c1a9ee45"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc5e64626e6682638d6e44398c9baf1d6ce6bc236d40b4b57255c9d3f9761f1f"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:437cfd39564744ae32ad5929e55b18ebd88817f9180e4cc05e7d53b75f79ce85"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62dd7df78e74d924952e2feb7357d826af8d2f307557a779d14ddf94d7311be8"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a66781d7e4cddcbbcfd64de3d41a61d6bdde370fc2e38623f30b2bd539e84a9f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:482fe06e9a3fffbcd41950f9d890034b4a54395c60b5e61fae875d37a699813f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e4f9373c500dfc02feea39f7a56e4f543e670212102cc2eeb51d3a99c7ffbde6"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e69bb81de06827147b7bfbaeb284d85219fa92d9f097e32cc73675f279d70188"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7613d9977d2ab4a9141dde4a149f4357e4065949674c5649f920fec86ecb393e"}, + {file = "frozenlist-1.6.0-cp313-cp313-win32.whl", hash = "sha256:4def87ef6d90429f777c9d9de3961679abf938cb6b7b63d4a7eb8a268babfce4"}, + {file = "frozenlist-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:37a8a52c3dfff01515e9bbbee0e6063181362f9de3db2ccf9bc96189b557cbfd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:46138f5a0773d064ff663d273b309b696293d7a7c00a0994c5c13a5078134b64"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f88bc0a2b9c2a835cb888b32246c27cdab5740059fb3688852bf91e915399b91"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:777704c1d7655b802c7850255639672e90e81ad6fa42b99ce5ed3fbf45e338dd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ef8d41764c7de0dcdaf64f733a27352248493a85a80661f3c678acd27e31f2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:da5cb36623f2b846fb25009d9d9215322318ff1c63403075f812b3b2876c8506"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbb56587a16cf0fb8acd19e90ff9924979ac1431baea8681712716a8337577b0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6154c3ba59cda3f954c6333025369e42c3acd0c6e8b6ce31eb5c5b8116c07e0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e8246877afa3f1ae5c979fe85f567d220f86a50dc6c493b9b7d8191181ae01e"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0f6cce16306d2e117cf9db71ab3a9e8878a28176aeaf0dbe35248d97b28d0c"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1b8e8cd8032ba266f91136d7105706ad57770f3522eac4a111d77ac126a25a9b"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e2ada1d8515d3ea5378c018a5f6d14b4994d4036591a52ceaf1a1549dec8e1ad"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:cdb2c7f071e4026c19a3e32b93a09e59b12000751fc9b0b7758da899e657d215"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:03572933a1969a6d6ab509d509e5af82ef80d4a5d4e1e9f2e1cdd22c77a3f4d2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:77effc978947548b676c54bbd6a08992759ea6f410d4987d69feea9cd0919911"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a2bda8be77660ad4089caf2223fdbd6db1858462c4b85b67fbfa22102021e497"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:a4d96dc5bcdbd834ec6b0f91027817214216b5b30316494d2b1aebffb87c534f"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e18036cb4caa17ea151fd5f3d70be9d354c99eb8cf817a3ccde8a7873b074348"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:536a1236065c29980c15c7229fbb830dedf809708c10e159b8136534233545f0"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ed5e3a4462ff25ca84fb09e0fada8ea267df98a450340ead4c91b44857267d70"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e19c0fc9f4f030fcae43b4cdec9e8ab83ffe30ec10c79a4a43a04d1af6c5e1ad"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c608f833897501dac548585312d73a7dca028bf3b8688f0d712b7acfaf7fb3"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0dbae96c225d584f834b8d3cc688825911960f003a85cb0fd20b6e5512468c42"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:625170a91dd7261a1d1c2a0c1a353c9e55d21cd67d0852185a5fef86587e6f5f"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1db8b2fc7ee8a940b547a14c10e56560ad3ea6499dc6875c354e2335812f739d"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4da6fc43048b648275a220e3a61c33b7fff65d11bdd6dcb9d9c145ff708b804c"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef8e7e8f2f3820c5f175d70fdd199b79e417acf6c72c5d0aa8f63c9f721646f"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa733d123cc78245e9bb15f29b44ed9e5780dc6867cfc4e544717b91f980af3b"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ba7f8d97152b61f22d7f59491a781ba9b177dd9f318486c5fbc52cde2db12189"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:56a0b8dd6d0d3d971c91f1df75e824986667ccce91e20dca2023683814344791"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5c9e89bf19ca148efcc9e3c44fd4c09d5af85c8a7dd3dbd0da1cb83425ef4983"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1330f0a4376587face7637dfd245380a57fe21ae8f9d360c1c2ef8746c4195fa"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2187248203b59625566cac53572ec8c2647a140ee2738b4e36772930377a533c"}, + {file = "frozenlist-1.6.0-cp39-cp39-win32.whl", hash = "sha256:2b8cf4cfea847d6c12af06091561a89740f1f67f331c3fa8623391905e878530"}, + {file = "frozenlist-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:1255d5d64328c5a0d066ecb0f02034d086537925f1f04b50b1ae60d37afbf572"}, + {file = "frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191"}, + {file = "frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68"}, ] [[package]] name = "google-api-core" -version = "2.24.1" +version = "2.24.2" description = "Google API client core library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_api_core-2.24.1-py3-none-any.whl", hash = "sha256:bc78d608f5a5bf853b80bd70a795f703294de656c096c0968320830a4bc280f1"}, - {file = "google_api_core-2.24.1.tar.gz", hash = "sha256:f8b36f5456ab0dd99a1b693a40a31d1e7757beea380ad1b38faaf8941eae9d8a"}, + {file = "google_api_core-2.24.2-py3-none-any.whl", hash = "sha256:810a63ac95f3c441b7c0e43d344e372887f62ce9071ba972eacf32672e072de9"}, + {file = "google_api_core-2.24.2.tar.gz", hash = "sha256:81718493daf06d96d6bc76a91c23874dbf2fac0adbbf542831b805ee6e974696"}, ] [package.dependencies] -google-auth = ">=2.14.1,<3.0.dev0" -googleapis-common-protos = ">=1.56.2,<2.0.dev0" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" -requests = ">=2.18.0,<3.0.0.dev0" +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.56.2,<2.0.0" +proto-plus = ">=1.22.3,<2.0.0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" +requests = ">=2.18.0,<3.0.0" [package.extras] async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.dev0)"] @@ -2091,14 +2109,14 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.161.0" +version = "2.163.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_api_python_client-2.161.0-py2.py3-none-any.whl", hash = "sha256:9476a5a4f200bae368140453df40f9cda36be53fa7d0e9a9aac4cdb859a26448"}, - {file = "google_api_python_client-2.161.0.tar.gz", hash = "sha256:324c0cce73e9ea0a0d2afd5937e01b7c2d6a4d7e2579cdb6c384f9699d6c9f37"}, + {file = "google_api_python_client-2.163.0-py2.py3-none-any.whl", hash = "sha256:080e8bc0669cb4c1fb8efb8da2f5b91a2625d8f0e7796cfad978f33f7016c6c4"}, + {file = "google_api_python_client-2.163.0.tar.gz", hash = "sha256:88dee87553a2d82176e2224648bf89272d536c8f04dcdda37ef0a71473886dd7"}, ] [package.dependencies] @@ -2110,14 +2128,14 @@ uritemplate = ">=3.0.1,<5" [[package]] name = "google-auth" -version = "2.38.0" +version = "2.39.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a"}, - {file = "google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4"}, + {file = "google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2"}, + {file = "google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7"}, ] [package.dependencies] @@ -2126,12 +2144,14 @@ pyasn1-modules = ">=0.2.1" rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] enterprise-cert = ["cryptography", "pyopenssl"] -pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] [[package]] name = "google-auth-httplib2" @@ -2151,32 +2171,32 @@ httplib2 = ">=0.19.0" [[package]] name = "googleapis-common-protos" -version = "1.66.0" +version = "1.70.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, - {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, + {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"}, + {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"}, ] [package.dependencies] -protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "gprof2dot" -version = "2024.6.6" +version = "2025.4.14" description = "Generate a dot graph from the output of several profilers." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "gprof2dot-2024.6.6-py2.py3-none-any.whl", hash = "sha256:45b14ad7ce64e299c8f526881007b9eb2c6b75505d5613e96e66ee4d5ab33696"}, - {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, + {file = "gprof2dot-2025.4.14-py3-none-any.whl", hash = "sha256:0742e4c0b4409a5e8777e739388a11e1ed3750be86895655312ea7c20bd0090e"}, + {file = "gprof2dot-2025.4.14.tar.gz", hash = "sha256:35743e2d2ca027bf48fa7cba37021aaf4a27beeae1ae8e05a50b55f1f921a6ce"}, ] [[package]] @@ -2257,14 +2277,14 @@ files = [ [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.8" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, + {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, ] [package.dependencies] @@ -2347,14 +2367,14 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "8.5.0" +version = "8.6.1" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, ] [package.dependencies] @@ -2366,7 +2386,7 @@ cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] @@ -2383,14 +2403,14 @@ files = [ [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -2501,19 +2521,19 @@ referencing = ">=0.31.0" [[package]] name = "kombu" -version = "5.4.2" +version = "5.5.3" description = "Messaging library for Python." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, - {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, + {file = "kombu-5.5.3-py3-none-any.whl", hash = "sha256:5b0dbceb4edee50aa464f59469d34b97864be09111338cfb224a10b6a163909b"}, + {file = "kombu-5.5.3.tar.gz", hash = "sha256:021a0e11fcfcd9b0260ef1fb64088c0e92beb976eb59c1dfca7ddd4ad4562ea2"}, ] [package.dependencies] amqp = ">=5.1.1,<6.0.0" -tzdata = {version = "*", markers = "python_version >= \"3.9\""} +tzdata = {version = ">=2025.2", markers = "python_version >= \"3.9\""} vine = "5.1.0" [package.extras] @@ -2521,15 +2541,16 @@ azureservicebus = ["azure-servicebus (>=7.10.0)"] azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] confluentkafka = ["confluent-kafka (>=2.2.0)"] consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.67.0)", "protobuf (==4.25.5)"] librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] mongodb = ["pymongo (>=4.1.1)"] msgpack = ["msgpack (==1.1.0)"] pyro = ["pyro4 (==4.82)"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] -slmq = ["softlayer-messaging (>=1.0.3)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<=5.2.1)"] +slmq = ["softlayer_messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] -sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "urllib3 (>=1.26.16)"] +sqs = ["boto3 (>=1.26.143)", "urllib3 (>=1.26.16)"] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=2.8.0)"] @@ -2817,18 +2838,18 @@ microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" [[package]] name = "msal" -version = "1.31.1" +version = "1.32.0" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "msal-1.31.1-py3-none-any.whl", hash = "sha256:29d9882de247e96db01386496d59f29035e5e841bcac892e6d7bf4390bf6bd17"}, - {file = "msal-1.31.1.tar.gz", hash = "sha256:11b5e6a3f802ffd3a72107203e20c4eac6ef53401961b880af2835b723d80578"}, + {file = "msal-1.32.0-py3-none-any.whl", hash = "sha256:9dbac5384a10bbbf4dae5c7ea0d707d14e087b92c5aa4954b3feaa2d1aa0bcb7"}, + {file = "msal-1.32.0.tar.gz", hash = "sha256:5445fe3af1da6be484991a7ab32eaa82461dc2347de105b76af92c610c3335c2"}, ] [package.dependencies] -cryptography = ">=2.5,<46" +cryptography = ">=2.5,<47" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" @@ -2837,30 +2858,32 @@ broker = ["pymsalruntime (>=0.14,<0.18) ; python_version >= \"3.6\" and platform [[package]] name = "msal-extensions" -version = "1.2.0" +version = "1.3.1" description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d"}, - {file = "msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef"}, + {file = "msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"}, + {file = "msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4"}, ] [package.dependencies] msal = ">=1.29,<2" -portalocker = ">=1.4,<3" + +[package.extras] +portalocker = ["portalocker (>=1.4,<4)"] [[package]] name = "msgraph-core" -version = "1.3.1" +version = "1.3.3" description = "Core component of the Microsoft Graph Python SDK" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msgraph_core-1.3.1-py3-none-any.whl", hash = "sha256:a6e3c19c36d43d00edfb49225647a357f8189351c226c3b7c020c5dfaa24171b"}, - {file = "msgraph_core-1.3.1.tar.gz", hash = "sha256:91c721b4c741d0e9a536e3c43e1cbd2254928b4d207e4f994e9cc7cb7a25bd74"}, + {file = "msgraph_core-1.3.3-py3-none-any.whl", hash = "sha256:9dbbc0c88e174c1d5da1c17d286965d6b26ebaf24996c7af64a39e2069006cf6"}, + {file = "msgraph_core-1.3.3.tar.gz", hash = "sha256:a3226b08b4cf9b6dbb16b868be21d5f82d8ee514ae8e46d9f0cad896159ef8d3"}, ] [package.dependencies] @@ -2874,26 +2897,23 @@ dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"] [[package]] name = "msgraph-sdk" -version = "1.18.0" +version = "1.23.0" description = "The Microsoft Graph Python SDK" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msgraph_sdk-1.18.0-py3-none-any.whl", hash = "sha256:f09b015bb9d7690bc6f30c9a28f9a414107aaf06be4952c27b3653dcdf33f2a3"}, - {file = "msgraph_sdk-1.18.0.tar.gz", hash = "sha256:ef49166ada7b459b5a843ceb3d253c1ab99d8987ebf3112147eb6cbcaa101793"}, + {file = "msgraph_sdk-1.23.0-py3-none-any.whl", hash = "sha256:58e0047b4ca59fd82022c02cd73fec0170a3d84f3b76721e3db2a0314df9a58a"}, + {file = "msgraph_sdk-1.23.0.tar.gz", hash = "sha256:6dd1ba9a46f5f0ce8599fd9610133adbd9d1493941438b5d3632fce9e55ed607"}, ] [package.dependencies] azure-identity = ">=1.12.0" -microsoft-kiota-abstractions = ">=1.3.0,<2.0.0" -microsoft-kiota-authentication-azure = ">=1.0.0,<2.0.0" -microsoft-kiota-http = ">=1.0.0,<2.0.0" -microsoft-kiota-serialization-form = ">=0.1.0" -microsoft-kiota-serialization-json = ">=1.3.0,<2.0.0" -microsoft-kiota-serialization-multipart = ">=0.1.0" -microsoft-kiota-serialization-text = ">=1.0.0,<2.0.0" -msgraph_core = ">=1.0.0" +microsoft-kiota-serialization-form = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-json = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-multipart = ">=1.8.0,<2.0.0" +microsoft-kiota-serialization-text = ">=1.8.0,<2.0.0" +msgraph_core = ">=1.3.1" [package.extras] dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"] @@ -2922,104 +2942,116 @@ async = ["aiodns ; python_version >= \"3.5\"", "aiohttp (>=3.0) ; python_version [[package]] name = "multidict" -version = "6.1.0" +version = "6.4.3" description = "multidict implementation" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32a998bd8a64ca48616eac5a8c1cc4fa38fb244a3facf2eeb14abe186e0f6cc5"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a54ec568f1fc7f3c313c2f3b16e5db346bf3660e1309746e7fccbbfded856188"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a7be07e5df178430621c716a63151165684d3e9958f2bbfcb644246162007ab7"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b128dbf1c939674a50dd0b28f12c244d90e5015e751a4f339a96c54f7275e291"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9cb19dfd83d35b6ff24a4022376ea6e45a2beba8ef3f0836b8a4b288b6ad685"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cf62f8e447ea2c1395afa289b332e49e13d07435369b6f4e41f887db65b40bf"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:909f7d43ff8f13d1adccb6a397094adc369d4da794407f8dd592c51cf0eae4b1"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bb8f8302fbc7122033df959e25777b0b7659b1fd6bcb9cb6bed76b5de67afef"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:224b79471b4f21169ea25ebc37ed6f058040c578e50ade532e2066562597b8a9"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a7bd27f7ab3204f16967a6f899b3e8e9eb3362c0ab91f2ee659e0345445e0078"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:99592bd3162e9c664671fd14e578a33bfdba487ea64bcb41d281286d3c870ad7"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a62d78a1c9072949018cdb05d3c533924ef8ac9bcb06cbf96f6d14772c5cd451"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ccdde001578347e877ca4f629450973c510e88e8865d5aefbcb89b852ccc666"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:eccb67b0e78aa2e38a04c5ecc13bab325a43e5159a181a9d1a6723db913cbb3c"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b6fcf6054fc4114a27aa865f8840ef3d675f9316e81868e0ad5866184a6cba5"}, + {file = "multidict-6.4.3-cp310-cp310-win32.whl", hash = "sha256:f92c7f62d59373cd93bc9969d2da9b4b21f78283b1379ba012f7ee8127b3152e"}, + {file = "multidict-6.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:b57e28dbc031d13916b946719f213c494a517b442d7b48b29443e79610acd887"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6f19170197cc29baccd33ccc5b5d6a331058796485857cf34f7635aa25fb0cd"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2882bf27037eb687e49591690e5d491e677272964f9ec7bc2abbe09108bdfb8"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbf226ac85f7d6b6b9ba77db4ec0704fde88463dc17717aec78ec3c8546c70ad"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e329114f82ad4b9dd291bef614ea8971ec119ecd0f54795109976de75c9a852"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1f4e0334d7a555c63f5c8952c57ab6f1c7b4f8c7f3442df689fc9f03df315c08"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:740915eb776617b57142ce0bb13b7596933496e2f798d3d15a20614adf30d229"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255dac25134d2b141c944b59a0d2f7211ca12a6d4779f7586a98b4b03ea80508"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e8535bd4d741039b5aad4285ecd9b902ef9e224711f0b6afda6e38d7ac02c7"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c433a33be000dd968f5750722eaa0991037be0be4a9d453eba121774985bc8"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4eb33b0bdc50acd538f45041f5f19945a1f32b909b76d7b117c0c25d8063df56"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:75482f43465edefd8a5d72724887ccdcd0c83778ded8f0cb1e0594bf71736cc0"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce5b3082e86aee80b3925ab4928198450d8e5b6466e11501fe03ad2191c6d777"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e413152e3212c4d39f82cf83c6f91be44bec9ddea950ce17af87fbf4e32ca6b2"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8aac2eeff69b71f229a405c0a4b61b54bade8e10163bc7b44fcd257949620618"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab583ac203af1d09034be41458feeab7863c0635c650a16f15771e1386abf2d7"}, + {file = "multidict-6.4.3-cp311-cp311-win32.whl", hash = "sha256:1b2019317726f41e81154df636a897de1bfe9228c3724a433894e44cd2512378"}, + {file = "multidict-6.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:43173924fa93c7486402217fab99b60baf78d33806af299c56133a3755f69589"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f1c2f58f08b36f8475f3ec6f5aeb95270921d418bf18f90dffd6be5c7b0e676"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:26ae9ad364fc61b936fb7bf4c9d8bd53f3a5b4417142cd0be5c509d6f767e2f1"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:659318c6c8a85f6ecfc06b4e57529e5a78dfdd697260cc81f683492ad7e9435a"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1eb72c741fd24d5a28242ce72bb61bc91f8451877131fa3fe930edb195f7054"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cd06d88cb7398252284ee75c8db8e680aa0d321451132d0dba12bc995f0adcc"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4543d8dc6470a82fde92b035a92529317191ce993533c3c0c68f56811164ed07"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30a3ebdc068c27e9d6081fca0e2c33fdf132ecea703a72ea216b81a66860adde"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b038f10e23f277153f86f95c777ba1958bcd5993194fda26a1d06fae98b2f00c"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c605a2b2dc14282b580454b9b5d14ebe0668381a3a26d0ac39daa0ca115eb2ae"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bd2b875f4ca2bb527fe23e318ddd509b7df163407b0fb717df229041c6df5d3"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c2e98c840c9c8e65c0e04b40c6c5066c8632678cd50c8721fdbcd2e09f21a507"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66eb80dd0ab36dbd559635e62fba3083a48a252633164857a1d1684f14326427"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c23831bdee0a2a3cf21be057b5e5326292f60472fb6c6f86392bbf0de70ba731"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1535cec6443bfd80d028052e9d17ba6ff8a5a3534c51d285ba56c18af97e9713"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b73e7227681f85d19dec46e5b881827cd354aabe46049e1a61d2f9aaa4e285a"}, + {file = "multidict-6.4.3-cp312-cp312-win32.whl", hash = "sha256:8eac0c49df91b88bf91f818e0a24c1c46f3622978e2c27035bfdca98e0e18124"}, + {file = "multidict-6.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:11990b5c757d956cd1db7cb140be50a63216af32cd6506329c2c59d732d802db"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a76534263d03ae0cfa721fea40fd2b5b9d17a6f85e98025931d41dc49504474"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:805031c2f599eee62ac579843555ed1ce389ae00c7e9f74c2a1b45e0564a88dd"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c56c179839d5dcf51d565132185409d1d5dd8e614ba501eb79023a6cab25576b"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c64f4ddb3886dd8ab71b68a7431ad4aa01a8fa5be5b11543b29674f29ca0ba3"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3002a856367c0b41cad6784f5b8d3ab008eda194ed7864aaa58f65312e2abcac"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d75e621e7d887d539d6e1d789f0c64271c250276c333480a9e1de089611f790"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:995015cf4a3c0d72cbf453b10a999b92c5629eaf3a0c3e1efb4b5c1f602253bb"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b0fabae7939d09d7d16a711468c385272fa1b9b7fb0d37e51143585d8e72e0"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61ed4d82f8a1e67eb9eb04f8587970d78fe7cddb4e4d6230b77eda23d27938f9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:062428944a8dc69df9fdc5d5fc6279421e5f9c75a9ee3f586f274ba7b05ab3c8"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b90e27b4674e6c405ad6c64e515a505c6d113b832df52fdacb6b1ffd1fa9a1d1"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7d50d4abf6729921e9613d98344b74241572b751c6b37feed75fb0c37bd5a817"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:43fe10524fb0a0514be3954be53258e61d87341008ce4914f8e8b92bee6f875d"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:236966ca6c472ea4e2d3f02f6673ebfd36ba3f23159c323f5a496869bc8e47c9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:422a5ec315018e606473ba1f5431e064cf8b2a7468019233dcf8082fabad64c8"}, + {file = "multidict-6.4.3-cp313-cp313-win32.whl", hash = "sha256:f901a5aace8e8c25d78960dcc24c870c8d356660d3b49b93a78bf38eb682aac3"}, + {file = "multidict-6.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:1c152c49e42277bc9a2f7b78bd5fa10b13e88d1b0328221e7aef89d5c60a99a5"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:be8751869e28b9c0d368d94f5afcb4234db66fe8496144547b4b6d6a0645cfc6"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d4b31f8a68dccbcd2c0ea04f0e014f1defc6b78f0eb8b35f2265e8716a6df0c"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:032efeab3049e37eef2ff91271884303becc9e54d740b492a93b7e7266e23756"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e78006af1a7c8a8007e4f56629d7252668344442f66982368ac06522445e375"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:daeac9dd30cda8703c417e4fddccd7c4dc0c73421a0b54a7da2713be125846be"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f6f90700881438953eae443a9c6f8a509808bc3b185246992c4233ccee37fea"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f84627997008390dd15762128dcf73c3365f4ec0106739cde6c20a07ed198ec8"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3307b48cd156153b117c0ea54890a3bdbf858a5b296ddd40dc3852e5f16e9b02"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead46b0fa1dcf5af503a46e9f1c2e80b5d95c6011526352fa5f42ea201526124"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1748cb2743bedc339d63eb1bca314061568793acd603a6e37b09a326334c9f44"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:acc9fa606f76fc111b4569348cc23a771cb52c61516dcc6bcef46d612edb483b"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:31469d5832b5885adeb70982e531ce86f8c992334edd2f2254a10fa3182ac504"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ba46b51b6e51b4ef7bfb84b82f5db0dc5e300fb222a8a13b8cd4111898a869cf"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:389cfefb599edf3fcfd5f64c0410da686f90f5f5e2c4d84e14f6797a5a337af4"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:64bc2bbc5fba7b9db5c2c8d750824f41c6994e3882e6d73c903c2afa78d091e4"}, + {file = "multidict-6.4.3-cp313-cp313t-win32.whl", hash = "sha256:0ecdc12ea44bab2807d6b4a7e5eef25109ab1c82a8240d86d3c1fc9f3b72efd5"}, + {file = "multidict-6.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7146a8742ea71b5d7d955bffcef58a9e6e04efba704b52a460134fefd10a8208"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5427a2679e95a642b7f8b0f761e660c845c8e6fe3141cddd6b62005bd133fc21"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:24a8caa26521b9ad09732972927d7b45b66453e6ebd91a3c6a46d811eeb7349b"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6b5a272bc7c36a2cd1b56ddc6bff02e9ce499f9f14ee4a45c45434ef083f2459"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf74dc5e212b8c75165b435c43eb0d5e81b6b300a938a4eb82827119115e840"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9f35de41aec4b323c71f54b0ca461ebf694fb48bec62f65221f52e0017955b39"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae93e0ff43b6f6892999af64097b18561691ffd835e21a8348a441e256592e1f"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e3929269e9d7eff905d6971d8b8c85e7dbc72c18fb99c8eae6fe0a152f2e343"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6214fe1750adc2a1b801a199d64b5a67671bf76ebf24c730b157846d0e90d2"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d79cf5c0c6284e90f72123f4a3e4add52d6c6ebb4a9054e88df15b8d08444c6"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2427370f4a255262928cd14533a70d9738dfacadb7563bc3b7f704cc2360fc4e"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:fbd8d737867912b6c5f99f56782b8cb81f978a97b4437a1c476de90a3e41c9a1"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0ee1bf613c448997f73fc4efb4ecebebb1c02268028dd4f11f011f02300cf1e8"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578568c4ba5f2b8abd956baf8b23790dbfdc953e87d5b110bce343b4a54fc9e7"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a059ad6b80de5b84b9fa02a39400319e62edd39d210b4e4f8c4f1243bdac4752"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dd53893675b729a965088aaadd6a1f326a72b83742b056c1065bdd2e2a42b4df"}, + {file = "multidict-6.4.3-cp39-cp39-win32.whl", hash = "sha256:abcfed2c4c139f25c2355e180bcc077a7cae91eefbb8b3927bb3f836c9586f1f"}, + {file = "multidict-6.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:b1b389ae17296dd739015d5ddb222ee99fd66adeae910de21ac950e00979d897"}, + {file = "multidict-6.4.3-py3-none-any.whl", hash = "sha256:59fe01ee8e2a1e8ceb3f6dbb216b09c8d9f4ef1c22c4fc825d045a147fa2ebc9"}, + {file = "multidict-6.4.3.tar.gz", hash = "sha256:3ada0b058c9f213c5f95ba301f922d402ac234f1111a7d8fd70f1b99f3c281ec"}, ] [[package]] @@ -3071,42 +3103,39 @@ reports = ["lxml"] [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] [[package]] name = "narwhals" -version = "1.25.2" +version = "1.35.0" description = "Extremely lightweight compatibility layer between dataframe libraries" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "narwhals-1.25.2-py3-none-any.whl", hash = "sha256:e645f7fc1f8c0a3563a6cdcd0191586cdf88470ad90f0818abba7ceb6c181b00"}, - {file = "narwhals-1.25.2.tar.gz", hash = "sha256:37594746fc06fe4a588967a34a2974b1f3a7ad6ff1571b6e31ac5e58c9591000"}, + {file = "narwhals-1.35.0-py3-none-any.whl", hash = "sha256:7562af132fa3f8aaaf34dc96d7ec95bdca29d1c795e8fcf14e01edf1d32122bc"}, + {file = "narwhals-1.35.0.tar.gz", hash = "sha256:07477d18487fbc940243b69818a177ed7119b737910a8a254fb67688b48a7c96"}, ] [package.extras] -core = ["duckdb", "pandas", "polars", "pyarrow", "pyarrow-stubs"] cudf = ["cudf (>=24.10.0)"] dask = ["dask[dataframe] (>=2024.8)"] -dev = ["covdefaults", "hypothesis", "pre-commit", "pytest", "pytest-cov", "pytest-env", "pytest-randomly", "typing-extensions"] -docs = ["black", "duckdb", "jinja2", "markdown-exec[ansi]", "mkdocs", "mkdocs-autorefs", "mkdocs-material", "mkdocstrings[python]", "pandas", "polars (>=1.0.0)", "pyarrow"] duckdb = ["duckdb (>=1.0)"] -extra = ["scikit-learn"] ibis = ["ibis-framework (>=6.0.0)", "packaging", "pyarrow-hotfix", "rich"] modin = ["modin"] pandas = ["pandas (>=0.25.3)"] polars = ["polars (>=0.20.3)"] pyarrow = ["pyarrow (>=11.0.0)"] pyspark = ["pyspark (>=3.5.0)"] +sqlframe = ["sqlframe (>=3.22.0)"] [[package]] name = "nest-asyncio" @@ -3194,63 +3223,63 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "opentelemetry-api" -version = "1.30.0" +version = "1.32.1" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_api-1.30.0-py3-none-any.whl", hash = "sha256:d5f5284890d73fdf47f843dda3210edf37a38d66f44f2b5aedc1e89ed455dc09"}, - {file = "opentelemetry_api-1.30.0.tar.gz", hash = "sha256:375893400c1435bf623f7dfb3bcd44825fe6b56c34d0667c542ea8257b1a1240"}, + {file = "opentelemetry_api-1.32.1-py3-none-any.whl", hash = "sha256:bbd19f14ab9f15f0e85e43e6a958aa4cb1f36870ee62b7fd205783a112012724"}, + {file = "opentelemetry_api-1.32.1.tar.gz", hash = "sha256:a5be71591694a4d9195caf6776b055aa702e964d961051a0715d05f8632c32fb"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=8.5.0" +importlib-metadata = ">=6.0,<8.7.0" [[package]] name = "opentelemetry-sdk" -version = "1.30.0" +version = "1.32.1" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_sdk-1.30.0-py3-none-any.whl", hash = "sha256:14fe7afc090caad881addb6926cec967129bd9260c4d33ae6a217359f6b61091"}, - {file = "opentelemetry_sdk-1.30.0.tar.gz", hash = "sha256:c9287a9e4a7614b9946e933a67168450b9ab35f08797eb9bc77d998fa480fa18"}, + {file = "opentelemetry_sdk-1.32.1-py3-none-any.whl", hash = "sha256:bba37b70a08038613247bc42beee5a81b0ddca422c7d7f1b097b32bf1c7e2f17"}, + {file = "opentelemetry_sdk-1.32.1.tar.gz", hash = "sha256:8ef373d490961848f525255a42b193430a0637e064dd132fd2a014d94792a092"}, ] [package.dependencies] -opentelemetry-api = "1.30.0" -opentelemetry-semantic-conventions = "0.51b0" +opentelemetry-api = "1.32.1" +opentelemetry-semantic-conventions = "0.53b1" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.51b0" +version = "0.53b1" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_semantic_conventions-0.51b0-py3-none-any.whl", hash = "sha256:fdc777359418e8d06c86012c3dc92c88a6453ba662e941593adb062e48c2eeae"}, - {file = "opentelemetry_semantic_conventions-0.51b0.tar.gz", hash = "sha256:3fabf47f35d1fd9aebcdca7e6802d86bd5ebc3bc3408b7e3248dde6e87a18c47"}, + {file = "opentelemetry_semantic_conventions-0.53b1-py3-none-any.whl", hash = "sha256:21df3ed13f035f8f3ea42d07cbebae37020367a53b47f1ebee3b10a381a00208"}, + {file = "opentelemetry_semantic_conventions-0.53b1.tar.gz", hash = "sha256:4c5a6fede9de61211b2e9fc1e02e8acacce882204cd770177342b6a3be682992"}, ] [package.dependencies] deprecated = ">=1.2.6" -opentelemetry-api = "1.30.0" +opentelemetry-api = "1.32.1" [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -3356,31 +3385,31 @@ setuptools = "*" [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.3.7" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] [[package]] name = "plotly" -version = "6.0.0" -description = "An open-source, interactive data visualization library for Python" +version = "6.0.1" +description = "An open-source interactive data visualization library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "plotly-6.0.0-py3-none-any.whl", hash = "sha256:f708871c3a9349a68791ff943a5781b1ec04de7769ea69068adcd9202e57653a"}, - {file = "plotly-6.0.0.tar.gz", hash = "sha256:c4aad38b8c3d65e4a5e7dd308b084143b9025c2cc9d5317fc1f1d30958db87d3"}, + {file = "plotly-6.0.1-py3-none-any.whl", hash = "sha256:4714db20fea57a435692c548a4eb4fae454f7daddf15f8d8ba7e1045681d7768"}, + {file = "plotly-6.0.1.tar.gz", hash = "sha256:dd8400229872b6e3c964b099be699f8d00c489a974f2cfccfad5e8240873366b"}, ] [package.dependencies] @@ -3407,35 +3436,15 @@ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] -name = "portalocker" -version = "2.10.1" -description = "Wraps the portalocker recipe for easy usage" +name = "prompt-toolkit" +version = "3.0.51" +description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, - {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, -] - -[package.dependencies] -pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} - -[package.extras] -docs = ["sphinx (>=1.7.1)"] -redis = ["redis"] -tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] - -[[package]] -name = "prompt-toolkit" -version = "3.0.50" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, - {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, + {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, + {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, ] [package.dependencies] @@ -3443,138 +3452,152 @@ wcwidth = "*" [[package]] name = "propcache" -version = "0.2.1" +version = "0.3.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, - {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, - {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, - {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, - {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, - {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, - {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, - {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, - {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, - {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, - {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, - {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, - {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, + {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, + {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, + {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, + {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, + {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, + {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, + {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, + {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, + {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, + {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, + {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, + {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, + {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, + {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, ] [[package]] name = "proto-plus" -version = "1.26.0" +version = "1.26.1" description = "Beautiful, Pythonic protocol buffers" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "proto_plus-1.26.0-py3-none-any.whl", hash = "sha256:bf2dfaa3da281fc3187d12d224c707cb57214fb2c22ba854eb0c105a3fb2d4d7"}, - {file = "proto_plus-1.26.0.tar.gz", hash = "sha256:6e93d5f5ca267b54300880fff156b6a3386b3fa3f43b1da62e680fc0c586ef22"}, + {file = "proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66"}, + {file = "proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012"}, ] [package.dependencies] -protobuf = ">=3.19.0,<6.0.0dev" +protobuf = ">=3.19.0,<7.0.0" [package.extras] testing = ["google-api-core (>=1.31.5)"] [[package]] name = "protobuf" -version = "5.29.3" +version = "6.30.2" description = "" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"}, - {file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"}, - {file = "protobuf-5.29.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e"}, - {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84"}, - {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f"}, - {file = "protobuf-5.29.3-cp38-cp38-win32.whl", hash = "sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252"}, - {file = "protobuf-5.29.3-cp38-cp38-win_amd64.whl", hash = "sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107"}, - {file = "protobuf-5.29.3-cp39-cp39-win32.whl", hash = "sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7"}, - {file = "protobuf-5.29.3-cp39-cp39-win_amd64.whl", hash = "sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da"}, - {file = "protobuf-5.29.3-py3-none-any.whl", hash = "sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f"}, - {file = "protobuf-5.29.3.tar.gz", hash = "sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620"}, + {file = "protobuf-6.30.2-cp310-abi3-win32.whl", hash = "sha256:b12ef7df7b9329886e66404bef5e9ce6a26b54069d7f7436a0853ccdeb91c103"}, + {file = "protobuf-6.30.2-cp310-abi3-win_amd64.whl", hash = "sha256:7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9"}, + {file = "protobuf-6.30.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:0eb523c550a66a09a0c20f86dd554afbf4d32b02af34ae53d93268c1f73bc65b"}, + {file = "protobuf-6.30.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:50f32cc9fd9cb09c783ebc275611b4f19dfdfb68d1ee55d2f0c7fa040df96815"}, + {file = "protobuf-6.30.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4f6c687ae8efae6cf6093389a596548214467778146b7245e886f35e1485315d"}, + {file = "protobuf-6.30.2-cp39-cp39-win32.whl", hash = "sha256:524afedc03b31b15586ca7f64d877a98b184f007180ce25183d1a5cb230ee72b"}, + {file = "protobuf-6.30.2-cp39-cp39-win_amd64.whl", hash = "sha256:acec579c39c88bd8fbbacab1b8052c793efe83a0a5bd99db4a31423a25c0a0e2"}, + {file = "protobuf-6.30.2-py3-none-any.whl", hash = "sha256:ae86b030e69a98e08c77beab574cbcb9fff6d031d57209f574a5aea1445f4b51"}, + {file = "protobuf-6.30.2.tar.gz", hash = "sha256:35c859ae076d8c56054c25b59e5e59638d86545ed6e2b6efac6be0b6ea3ba048"}, ] [[package]] name = "prowler" -version = "5.4.0" +version = "5.6.0" description = "Prowler is an Open Source security tool to perform AWS, GCP and Azure security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness. It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks." optional = false python-versions = ">3.9.1,<3.13" @@ -3585,23 +3608,23 @@ develop = false [package.dependencies] alive-progress = "3.2.0" awsipranges = "0.3.3" -azure-identity = "1.19.0" +azure-identity = "1.21.0" azure-keyvault-keys = "4.10.0" -azure-mgmt-applicationinsights = "4.0.0" +azure-mgmt-applicationinsights = "4.1.0" azure-mgmt-authorization = "4.0.0" azure-mgmt-compute = "34.0.0" -azure-mgmt-containerregistry = "10.3.0" -azure-mgmt-containerservice = "34.0.0" +azure-mgmt-containerregistry = "12.0.0" +azure-mgmt-containerservice = "34.1.0" azure-mgmt-cosmosdb = "9.7.0" azure-mgmt-keyvault = "10.3.1" azure-mgmt-monitor = "6.0.2" azure-mgmt-network = "28.1.0" azure-mgmt-rdbms = "10.1.0" -azure-mgmt-resource = "23.2.0" +azure-mgmt-resource = "23.3.0" azure-mgmt-search = "9.1.0" azure-mgmt-security = "7.0.0" azure-mgmt-sql = "3.0.1" -azure-mgmt-storage = "21.2.1" +azure-mgmt-storage = "22.1.1" azure-mgmt-subscription = "3.1.1" azure-mgmt-web = "8.0.0" azure-storage-blob = "12.24.1" @@ -3612,29 +3635,29 @@ cryptography = "44.0.1" dash = "2.18.2" dash-bootstrap-components = "1.6.0" detect-secrets = "1.5.0" -google-api-python-client = "2.161.0" +google-api-python-client = "2.163.0" google-auth-httplib2 = ">=0.1,<0.3" jsonschema = "4.23.0" kubernetes = "32.0.1" microsoft-kiota-abstractions = "1.9.2" -msgraph-sdk = "1.18.0" +msgraph-sdk = "1.23.0" numpy = "2.0.2" pandas = "2.2.3" py-ocsf-models = "0.3.1" pydantic = "1.10.21" -python-dateutil = "^2.9.0.post0" +python-dateutil = ">=2.9.0.post0,<3.0.0" pytz = "2025.1" schema = "0.7.7" shodan = "1.31.0" slack-sdk = "3.34.0" tabulate = "0.9.0" -tzlocal = "5.2" +tzlocal = "5.3.1" [package.source] type = "git" url = "https://github.com/prowler-cloud/prowler.git" reference = "master" -resolved_reference = "931df361bf5ee287139112f485580241099094cb" +resolved_reference = "0edf19928269b6d42d1c463ab13b90d7c21a65e4" [[package]] name = "psutil" @@ -3779,29 +3802,29 @@ files = [ [[package]] name = "pyasn1-modules" -version = "0.4.1" +version = "0.4.2" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, - {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.7.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycodestyle" -version = "2.12.1" +version = "2.13.0" description = "Python style guide checker" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, - {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, + {file = "pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9"}, + {file = "pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae"}, ] [[package]] @@ -3819,44 +3842,44 @@ files = [ [[package]] name = "pycurl" -version = "7.45.4" +version = "7.45.6" description = "PycURL -- A Python Interface To The cURL library" optional = false python-versions = ">=3.5" groups = ["main"] markers = "sys_platform != \"win32\" and platform_python_implementation == \"CPython\"" files = [ - {file = "pycurl-7.45.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:247b4af8eab7d04137a7f1a98391930e04ea93dc669b64db5625070fe15f80a3"}, - {file = "pycurl-7.45.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:561f88697f7540634b1c750146f37bdc0da367b15f6b4ab2bb780871ee6ab005"}, - {file = "pycurl-7.45.4-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b485fdaf78553f0b8e1c2803bb7dcbe47a7b47594f846fc7e9d3b94d794cfc89"}, - {file = "pycurl-7.45.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e7ae49b88a5d57485fbabef004534225dfe04dc15716a61fae1a0c7f46f2279e"}, - {file = "pycurl-7.45.4-cp310-cp310-win32.whl", hash = "sha256:d14f954ecd21a070038d65ef1c6d1d3ab220f952ff703d48313123222097615c"}, - {file = "pycurl-7.45.4-cp310-cp310-win_amd64.whl", hash = "sha256:2548c3291a33c821f0f80bf9989fc43b5d90fb78b534a7015c8419b83c6f5803"}, - {file = "pycurl-7.45.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6c0e22052946bbfa25be67f9d1d6639eff10781c89f0cf6f3ff2099273d1bad"}, - {file = "pycurl-7.45.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acf25cfdaf914db21a2a6e9e274b6d95e3fa2b6018c38f2c58c94b5d8ac3d1b7"}, - {file = "pycurl-7.45.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a39f28f031885485325034918386be352036c220ca45625c7e286d3938eb579d"}, - {file = "pycurl-7.45.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:9940e3234c1ca3d30f27a2202d325dbc25291605c98e9585100a351cacd935e8"}, - {file = "pycurl-7.45.4-cp311-cp311-win32.whl", hash = "sha256:ffd3262f98b8997ad04940061d5ebd8bab2362169b9440939c397e24a4a135b0"}, - {file = "pycurl-7.45.4-cp311-cp311-win_amd64.whl", hash = "sha256:1324a859b50bdb0abdbd5620e42f74240d0b7daf2d5925fa303695d9fc3ece18"}, - {file = "pycurl-7.45.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:731c46e7c0acffaab19f7c2ecc3d9e7ee337500e87b260b4e0b9fae2d90fa133"}, - {file = "pycurl-7.45.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13eb1643ab0bf4fdc539a2cdf1021029b07095d3196c5cee5a4271af268d3d31"}, - {file = "pycurl-7.45.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:df5f94c051c5a163fa85064559ca94979575e2da26740ff91c078c50c541c465"}, - {file = "pycurl-7.45.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:688d09ba2c6a0d4a749d192c43422839d73c40c85143c50cc65c944258fe0ba8"}, - {file = "pycurl-7.45.4-cp312-cp312-win32.whl", hash = "sha256:236600bfe2cd72efe47333add621286667e8fa027dadf1247349afbf30333e95"}, - {file = "pycurl-7.45.4-cp312-cp312-win_amd64.whl", hash = "sha256:26745c6c5ebdccfe8a828ac3fd4e6da6f5d2245696604f04529eb7894a02f4db"}, - {file = "pycurl-7.45.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bd493ce598f1dc76c8e50043c47debec27c583fa313a836b2d3667640f875d5"}, - {file = "pycurl-7.45.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f25d52c97dbca6ebea786f0961b49c1998fa05178abf1964a977c825b3d8ae6"}, - {file = "pycurl-7.45.4-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:13c4b18f44637859f34639493efd297a08670f45e4eec34ab2dcba724e3cb5fc"}, - {file = "pycurl-7.45.4-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0470bff6cc24d8c2f63c80931aa239463800871609dafc6bcc9ca10f5a12a04e"}, - {file = "pycurl-7.45.4-cp313-cp313-win32.whl", hash = "sha256:3452459668bd01d646385482362b021834a31c036aa1c02acd88924ddeff7d0d"}, - {file = "pycurl-7.45.4-cp313-cp313-win_amd64.whl", hash = "sha256:fd167f73d34beb0cb8064334aee76d9bdd13167b30be6d5d36fb07d0c8223b71"}, - {file = "pycurl-7.45.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b0e38e3eb83b0c891f391853f798fc6a97cb5a86a4a731df0b6320e539ae54ae"}, - {file = "pycurl-7.45.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d192a48b3cec2e13ad432196b65c22e99620db92feae39c0476635354eff68c6"}, - {file = "pycurl-7.45.4-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:57971d7215fc6fdedcfc092f880a59f04f52fcaf2fd329151b931623d7b59a9c"}, - {file = "pycurl-7.45.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:73df3eb5940a7fbf4cf62f7271e9f23a8e9f80e352c838ee9a8448a70c01d3f5"}, - {file = "pycurl-7.45.4-cp39-cp39-win32.whl", hash = "sha256:587a4891039803b5f48392066f97b7cd5e7e9a166187abb5cb4b4806fdb8fbef"}, - {file = "pycurl-7.45.4-cp39-cp39-win_amd64.whl", hash = "sha256:caec8b634763351dd4e1b729a71542b1e2de885d39710ba8e7202817a381b453"}, - {file = "pycurl-7.45.4.tar.gz", hash = "sha256:32c8e237069273f4260b6ae13d1e0f99daae938977016021565dc6e11050e803"}, + {file = "pycurl-7.45.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c31b390f1e2cd4525828f1bb78c1f825c0aab5d1588228ed71b22c4784bdb593"}, + {file = "pycurl-7.45.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:942b352b69184cb26920db48e0c5cb95af39874b57dbe27318e60f1e68564e37"}, + {file = "pycurl-7.45.6-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3441ee77e830267aa6e2bb43b29fd5f8a6bd6122010c76a6f0bf84462e9ea9c7"}, + {file = "pycurl-7.45.6-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:2a21e13278d7553a04b421676c458449f6c10509bebf04993f35154b06ee2b20"}, + {file = "pycurl-7.45.6-cp310-cp310-win32.whl", hash = "sha256:d0b5501d527901369aba307354530050f56cd102410f2a3bacd192dc12c645e3"}, + {file = "pycurl-7.45.6-cp310-cp310-win_amd64.whl", hash = "sha256:abe1b204a2f96f2eebeaf93411f03505b46d151ef6d9d89326e6dece7b3a008a"}, + {file = "pycurl-7.45.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f57ad26d6ab390391ad5030790e3f1a831c1ee54ad3bf969eb378f5957eeb0a"}, + {file = "pycurl-7.45.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6fd295f03c928da33a00f56c91765195155d2ac6f12878f6e467830b5dce5f5"}, + {file = "pycurl-7.45.6-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:334721ce1ccd71ff8e405470768b3d221b4393570ccc493fcbdbef4cd62e91ed"}, + {file = "pycurl-7.45.6-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0cd6b7794268c17f3c660162ed6381769ce0ad260331ef49191418dfc3a2d61a"}, + {file = "pycurl-7.45.6-cp311-cp311-win32.whl", hash = "sha256:357ea634395310085b9d5116226ac5ec218a6ceebf367c2451ebc8d63a6e9939"}, + {file = "pycurl-7.45.6-cp311-cp311-win_amd64.whl", hash = "sha256:878ae64484db18f8f10ba99bffc83fefb4fe8f5686448754f93ec32fa4e4ee93"}, + {file = "pycurl-7.45.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c872d4074360964697c39c1544fe8c91bfecbff27c1cdda1fee5498e5fdadcda"}, + {file = "pycurl-7.45.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56d1197eadd5774582b259cde4364357da71542758d8e917f91cc6ed7ed5b262"}, + {file = "pycurl-7.45.6-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8a99e56d2575aa74c48c0cd08852a65d5fc952798f76a34236256d5589bf5aa0"}, + {file = "pycurl-7.45.6-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c04230b9e9cfdca9cf3eb09a0bec6cf2f084640f1f1ca1929cca51411af85de2"}, + {file = "pycurl-7.45.6-cp312-cp312-win32.whl", hash = "sha256:ae893144b82d72d95c932ebdeb81fc7e9fde758e5ecd5dd10ad5b67f34a8b8ee"}, + {file = "pycurl-7.45.6-cp312-cp312-win_amd64.whl", hash = "sha256:56f841b6f2f7a8b2d3051b9ceebd478599dbea3c8d1de8fb9333c895d0c1eea5"}, + {file = "pycurl-7.45.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7c09b7180799af70fc1d4eed580cfb1b9f34fda9081f73a3e3bc9a0e5a4c0e9b"}, + {file = "pycurl-7.45.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:361bf94b2a057c7290f9ab84e935793ca515121fc012f4b6bef6c3b5e4ea4397"}, + {file = "pycurl-7.45.6-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:bb9eff0c7794af972da769a887c87729f1bcd8869297b1c01a2732febbb75876"}, + {file = "pycurl-7.45.6-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:26839d43dc7fff6b80e0067f185cc1d0e9be2ae6e2e2361ae8488cead5901c04"}, + {file = "pycurl-7.45.6-cp313-cp313-win32.whl", hash = "sha256:a721c2696a71b1aa5ecf82e6d0ade64bc7211b7317f1c9c66e82f82e2264d8b4"}, + {file = "pycurl-7.45.6-cp313-cp313-win_amd64.whl", hash = "sha256:f0198ebcda8686b3a0c66d490a687fa5fd466f8ecc2f20a0ed0931579538ae3d"}, + {file = "pycurl-7.45.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a554a2813d415a7bb9a996a6298f3829f57e987635dcab9f1197b2dccd0ab3b2"}, + {file = "pycurl-7.45.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f721e3394e5bd7079802ec1819b19c5be4842012268cc45afcb3884efb31cf0"}, + {file = "pycurl-7.45.6-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:81005c0f681d31d5af694d1d3c18bbf1bed0bc8b2bb10fb7388cb1378ba9bd6a"}, + {file = "pycurl-7.45.6-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:3fc0b505c37c7c54d88ced27e1d9e3241130987c24bf1611d9bbd9a3e499e07c"}, + {file = "pycurl-7.45.6-cp39-cp39-win32.whl", hash = "sha256:1309fc0f558a80ca444a3a5b0bdb1572a4d72b195233f0e65413b4d4dd78809b"}, + {file = "pycurl-7.45.6-cp39-cp39-win_amd64.whl", hash = "sha256:2d1a49418b8b4c61f52e06d97b9c16142b425077bd997a123a2ba9ef82553203"}, + {file = "pycurl-7.45.6.tar.gz", hash = "sha256:2b73e66b22719ea48ac08a93fc88e57ef36d46d03cb09d972063c9aa86bb74e6"}, ] [[package]] @@ -3943,14 +3966,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.9.0" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, - {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, + {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, + {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, ] [package.dependencies] @@ -3992,14 +4015,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" -version = "3.2.1" +version = "3.2.3" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, - {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, + {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, + {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, ] [package.extras] @@ -4099,14 +4122,14 @@ testing = ["Django", "django-configurations (>=2.0)"] [[package]] name = "pytest-docker-tools" -version = "3.1.3" +version = "3.1.9" description = "Docker integration tests for pytest" optional = false -python-versions = ">=3.7.0,<4.0.0" +python-versions = "<4.0.0,>=3.9.0" groups = ["main"] files = [ - {file = "pytest_docker_tools-3.1.3-py3-none-any.whl", hash = "sha256:63e659043160f41d89f94ea42616102594bcc85682aac394fcbc14f14cd1b189"}, - {file = "pytest_docker_tools-3.1.3.tar.gz", hash = "sha256:c7e28841839d67b3ac80ad7b345b953701d5ae61ffda97586114244292aeacc0"}, + {file = "pytest_docker_tools-3.1.9-py2.py3-none-any.whl", hash = "sha256:36f8e88d56d84ea177df68a175673681243dd991d2807fbf551d90f60341bfdb"}, + {file = "pytest_docker_tools-3.1.9.tar.gz", hash = "sha256:1b6a0cb633c20145731313335ef15bcf5571839c06726764e60cbe495324782b"}, ] [package.dependencies] @@ -4227,32 +4250,30 @@ files = [ [[package]] name = "pywin32" -version = "308" +version = "310" description = "Python for Window Extensions" optional = false python-versions = "*" groups = ["main", "dev"] +markers = "sys_platform == \"win32\"" files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, + {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"}, + {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"}, + {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"}, + {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, ] -markers = {main = "sys_platform == \"win32\" or platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} [[package]] name = "pyyaml" @@ -4426,14 +4447,14 @@ six = ">=1.7.0" [[package]] name = "rich" -version = "13.9.4" +version = "14.0.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" groups = ["dev"] files = [ - {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, - {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, + {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, + {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, ] [package.dependencies] @@ -4445,127 +4466,138 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.22.3" +version = "0.24.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, - {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, - {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, - {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, - {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, - {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, - {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, - {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, - {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, - {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, - {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, - {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, - {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875"}, + {file = "rpds_py-0.24.0-cp310-cp310-win32.whl", hash = "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07"}, + {file = "rpds_py-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718"}, + {file = "rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a"}, + {file = "rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56"}, + {file = "rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30"}, + {file = "rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9"}, + {file = "rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143"}, + {file = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45"}, + {file = "rpds_py-0.24.0-cp39-cp39-win32.whl", hash = "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103"}, + {file = "rpds_py-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f"}, + {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"}, ] [[package]] name = "rsa" -version = "4.9" +version = "4.9.1" description = "Pure-Python RSA implementation" optional = false -python-versions = ">=3.6,<4" +python-versions = "<4,>=3.6" groups = ["main"] files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, ] [package.dependencies] @@ -4757,14 +4789,14 @@ files = [ [[package]] name = "sentry-sdk" -version = "2.20.0" +version = "2.26.1" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"}, - {file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"}, + {file = "sentry_sdk-2.26.1-py2.py3-none-any.whl", hash = "sha256:e99390e3f217d13ddcbaeaed08789f1ca614d663b345b9da42e35ad6b60d696a"}, + {file = "sentry_sdk-2.26.1.tar.gz", hash = "sha256:759e019c41551a21519a95e6cef6d91fb4af1054761923dadaee2e6eca9c02c7"}, ] [package.dependencies] @@ -4809,24 +4841,25 @@ sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] +statsig = ["statsig (>=0.55.3)"] tornado = ["tornado (>=6)"] unleash = ["UnleashClient (>=6.0.1)"] [[package]] name = "setuptools" -version = "75.8.0" +version = "79.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, - {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, + {file = "setuptools-79.0.0-py3-none-any.whl", hash = "sha256:b9ab3a104bedb292323f53797b00864e10e434a3ab3906813a7169e4745b912a"}, + {file = "setuptools-79.0.0.tar.gz", hash = "sha256:9828422e7541213b0aacb6e10bbf9dd8febeaa45a48570e09b6d100e063fc9f9"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] @@ -4933,14 +4966,14 @@ files = [ [[package]] name = "stevedore" -version = "5.4.0" +version = "5.4.1" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857"}, - {file = "stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d"}, + {file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"}, + {file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"}, ] [package.dependencies] @@ -4963,14 +4996,14 @@ widechars = ["wcwidth"] [[package]] name = "tenacity" -version = "9.0.0" +version = "9.1.2" description = "Retry code until it succeeds" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, - {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, + {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, + {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, ] [package.extras] @@ -4979,14 +5012,14 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "tldextract" -version = "5.1.3" +version = "5.3.0" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75"}, - {file = "tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338"}, + {file = "tldextract-5.3.0-py3-none-any.whl", hash = "sha256:f70f31d10b55c83993f55e91ecb7c5d84532a8972f22ec578ecfbe5ea2292db2"}, + {file = "tldextract-5.3.0.tar.gz", hash = "sha256:b3d2b70a1594a0ecfa6967d57251527d58e00bb5a91a74387baa0d87a0678609"}, ] [package.dependencies] @@ -5035,14 +5068,14 @@ telegram = ["requests"] [[package]] name = "typer" -version = "0.15.1" +version = "0.15.2" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"}, - {file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"}, + {file = "typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc"}, + {file = "typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5"}, ] [package.dependencies] @@ -5053,39 +5086,39 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] [[package]] name = "tzdata" -version = "2025.1" +version = "2025.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main", "dev"] files = [ - {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, - {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, ] markers = {dev = "sys_platform == \"win32\""} [[package]] name = "tzlocal" -version = "5.2" +version = "5.3.1" description = "tzinfo object for the local timezone" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, - {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, + {file = "tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"}, + {file = "tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd"}, ] [package.dependencies] @@ -5108,14 +5141,14 @@ files = [ [[package]] name = "urllib3" -version = "2.3.0" +version = "2.4.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, - {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, + {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, + {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, ] [package.extras] @@ -5298,112 +5331,134 @@ files = [ [[package]] name = "xlsxwriter" -version = "3.2.2" +version = "3.2.3" description = "A Python module for creating Excel XLSX files." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "XlsxWriter-3.2.2-py3-none-any.whl", hash = "sha256:272ce861e7fa5e82a4a6ebc24511f2cb952fde3461f6c6e1a1e81d3272db1471"}, - {file = "xlsxwriter-3.2.2.tar.gz", hash = "sha256:befc7f92578a85fed261639fb6cde1fd51b79c5e854040847dde59d4317077dc"}, + {file = "XlsxWriter-3.2.3-py3-none-any.whl", hash = "sha256:593f8296e8a91790c6d0378ab08b064f34a642b3feb787cf6738236bd0a4860d"}, + {file = "xlsxwriter-3.2.3.tar.gz", hash = "sha256:ad6fd41bdcf1b885876b1f6b7087560aecc9ae5a9cc2ba97dcac7ab2e210d3d5"}, ] [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1f6670b9ae3daedb325fa55fbe31c22c8228f6e0b513772c2e1c623caa6ab22"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85a231fa250dfa3308f3c7896cc007a47bc76e9e8e8595c20b7426cac4884c62"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a06701b647c9939d7019acdfa7ebbfbb78ba6aa05985bb195ad716ea759a569"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7595498d085becc8fb9203aa314b136ab0516c7abd97e7d74f7bb4eb95042abe"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af5607159085dcdb055d5678fc2d34949bd75ae6ea6b4381e784bbab1c3aa195"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95b50910e496567434cb77a577493c26bce0f31c8a305135f3bda6a2483b8e10"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b594113a301ad537766b4e16a5a6750fcbb1497dcc1bc8a4daae889e6402a634"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:083ce0393ea173cd37834eb84df15b6853b555d20c52703e21fbababa8c129d2"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1a350a652bbbe12f666109fbddfdf049b3ff43696d18c9ab1531fbba1c977a"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fb0caeac4a164aadce342f1597297ec0ce261ec4532bbc5a9ca8da5622f53867"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d88cc43e923f324203f6ec14434fa33b85c06d18d59c167a0637164863b8e995"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e52d6ed9ea8fd3abf4031325dc714aed5afcbfa19ee4a89898d663c9976eb487"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ce360ae48a5e9961d0c730cf891d40698a82804e85f6e74658fb175207a77cb2"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:06d06c9d5b5bc3eb56542ceeba6658d31f54cf401e8468512447834856fb0e61"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c27d98f4e5c4060582f44e58309c1e55134880558f1add7a87c1bc36ecfade19"}, + {file = "yarl-1.20.0-cp310-cp310-win32.whl", hash = "sha256:f4d3fa9b9f013f7050326e165c3279e22850d02ae544ace285674cb6174b5d6d"}, + {file = "yarl-1.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc906b636239631d42eb8a07df8359905da02704a868983265603887ed68c076"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5"}, + {file = "yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6"}, + {file = "yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b"}, + {file = "yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64"}, + {file = "yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384"}, + {file = "yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62"}, + {file = "yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f"}, + {file = "yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac"}, + {file = "yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:119bca25e63a7725b0c9d20ac67ca6d98fa40e5a894bd5d4686010ff73397914"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35d20fb919546995f1d8c9e41f485febd266f60e55383090010f272aca93edcc"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:484e7a08f72683c0f160270566b4395ea5412b4359772b98659921411d32ad26"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d8a3d54a090e0fff5837cd3cc305dd8a07d3435a088ddb1f65e33b322f66a94"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0cf05ae2d3d87a8c9022f3885ac6dea2b751aefd66a4f200e408a61ae9b7f0d"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a884b8974729e3899d9287df46f015ce53f7282d8d3340fa0ed57536b440621c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d8aa8dd89ffb9a831fedbcb27d00ffd9f4842107d52dc9d57e64cb34073d5c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4e88d6c3c8672f45a30867817e4537df1bbc6f882a91581faf1f6d9f0f1b5a"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdb77efde644d6f1ad27be8a5d67c10b7f769804fff7a966ccb1da5a4de4b656"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4ba5e59f14bfe8d261a654278a0f6364feef64a794bd456a8c9e823071e5061c"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d0bf955b96ea44ad914bc792c26a0edcd71b4668b93cbcd60f5b0aeaaed06c64"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27359776bc359ee6eaefe40cb19060238f31228799e43ebd3884e9c589e63b20"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d9c7a1dc0a26efb33e1acb56c8849bd57a693b85f44774356c92d610369efa"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:faa709b66ae0e24c8e5134033187a972d849d87ed0a12a0366bedcc6b5dc14a5"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:44869ee8538208fe5d9342ed62c11cc6a7a1af1b3d0bb79bb795101b6e77f6e0"}, + {file = "yarl-1.20.0-cp39-cp39-win32.whl", hash = "sha256:b7fa0cb9fd27ffb1211cde944b41f5c67ab1c13a13ebafe470b1e206b8459da8"}, + {file = "yarl-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4fad6e5189c847820288286732075f213eabf81be4d08d6cc309912e62be5b7"}, + {file = "yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124"}, + {file = "yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [[package]] name = "zipp" @@ -5428,4 +5483,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.13" -content-hash = "0da43d42c9cdb0b990cfd184ba776e3ce2a5ee72fbd076e980d7111c772d6000" +content-hash = "f3ede96fb76c14d02da37c1132b41a14fa4045787807446fac2cd1750be193e0" diff --git a/api/pyproject.toml b/api/pyproject.toml index d8e74d6260..974a369ca2 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -35,7 +35,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.6.0" +version = "1.7.0" [project.scripts] celery = "src.backend.config.settings.celery" @@ -46,6 +46,7 @@ coverage = "7.5.4" django-silk = "5.3.2" docker = "7.1.0" freezegun = "1.5.1" +marshmallow = ">=3.15.0,<4.0.0" mypy = "1.10.1" pylint = "3.2.5" pytest = "8.2.2" diff --git a/api/src/backend/api/migrations/0017_m365_provider.py b/api/src/backend/api/migrations/0017_m365_provider.py new file mode 100644 index 0000000000..62817560c5 --- /dev/null +++ b/api/src/backend/api/migrations/0017_m365_provider.py @@ -0,0 +1,32 @@ +# Generated by Django 5.1.7 on 2025-04-16 08:47 + +from django.db import migrations + +import api.db_utils + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0016_finding_compliance_resource_details_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="provider", + name="provider", + field=api.db_utils.ProviderEnumField( + choices=[ + ("aws", "AWS"), + ("azure", "Azure"), + ("gcp", "GCP"), + ("kubernetes", "Kubernetes"), + ("m365", "M365"), + ], + default="aws", + ), + ), + migrations.RunSQL( + "ALTER TYPE provider ADD VALUE IF NOT EXISTS 'm365';", + reverse_sql=migrations.RunSQL.noop, + ), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 69b7ead46a..01f88178f0 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -191,6 +191,7 @@ class Provider(RowLevelSecurityProtectedModel): AZURE = "azure", _("Azure") GCP = "gcp", _("GCP") KUBERNETES = "kubernetes", _("Kubernetes") + M365 = "m365", _("M365") @staticmethod def validate_aws_uid(value): @@ -214,6 +215,15 @@ class Provider(RowLevelSecurityProtectedModel): pointer="/data/attributes/uid", ) + @staticmethod + def validate_m365_uid(value): + if not re.match(r"^[a-zA-Z0-9-]+\.onmicrosoft\.com$", value): + raise ModelValidationError( + detail="M365 tenant ID must be a valid domain.", + code="m365-uid", + pointer="/data/attributes/uid", + ) + @staticmethod def validate_gcp_uid(value): if not re.match(r"^[a-z][a-z0-9-]{5,29}$", value): diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 30c9dbb675..bb7c580815 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.6.0 + version: 1.7.0 description: |- Prowler API specification. @@ -83,11 +83,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -99,6 +101,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -106,6 +109,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -450,11 +454,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -466,6 +472,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -473,6 +480,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -962,11 +970,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -978,6 +988,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -985,6 +996,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -1395,11 +1407,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -1411,6 +1425,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -1418,6 +1433,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -2047,11 +2063,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -2063,6 +2081,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -2070,6 +2089,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -2204,11 +2224,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -2220,6 +2242,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -2227,6 +2250,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -2377,11 +2401,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -2393,6 +2419,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -2400,6 +2427,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -2863,11 +2891,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider__in] schema: @@ -3441,11 +3471,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -3457,6 +3489,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -3464,6 +3497,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -4167,11 +4201,13 @@ paths: - azure - gcp - kubernetes + - m365 description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 - in: query name: filter[provider_type__in] schema: @@ -4183,6 +4219,7 @@ paths: - azure - gcp - kubernetes + - m365 description: |- Multiple values may be separated by commas. @@ -4190,6 +4227,7 @@ paths: * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 explode: false style: form - in: query @@ -8347,6 +8385,33 @@ components: - client_id - client_secret - tenant_id + - type: object + title: M365 Static Credentials + properties: + client_id: + type: string + description: The Azure application (client) ID for authentication + in Azure AD. + client_secret: + type: string + description: The client secret associated with the application + (client) ID, providing secure access. + tenant_id: + type: string + description: The Azure tenant ID, representing the directory + where the application is registered. + user: + type: email + description: User microsoft email address. + encrypted_password: + type: string + description: User encrypted password. + required: + - client_id + - client_secret + - tenant_id + - user + - encrypted_password - type: object title: GCP Static Credentials properties: @@ -8814,12 +8879,14 @@ components: - azure - gcp - kubernetes + - m365 type: string description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 uid: type: string title: Unique identifier for the provider, set by the provider @@ -8926,12 +8993,14 @@ components: - azure - gcp - kubernetes + - m365 type: string description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 uid: type: string title: Unique identifier for the provider, set by the provider @@ -8969,12 +9038,14 @@ components: - azure - gcp - kubernetes + - m365 type: string description: |- * `aws` - AWS * `azure` - Azure * `gcp` - GCP * `kubernetes` - Kubernetes + * `m365` - M365 uid: type: string minLength: 3 @@ -9559,6 +9630,33 @@ components: - client_id - client_secret - tenant_id + - type: object + title: M365 Static Credentials + properties: + client_id: + type: string + description: The Azure application (client) ID for authentication + in Azure AD. + client_secret: + type: string + description: The client secret associated with the application + (client) ID, providing secure access. + tenant_id: + type: string + description: The Azure tenant ID, representing the directory where + the application is registered. + user: + type: email + description: User microsoft email address. + encrypted_password: + type: string + description: User encrypted password. + required: + - client_id + - client_secret + - tenant_id + - user + - encrypted_password - type: object title: GCP Static Credentials properties: @@ -9741,6 +9839,33 @@ components: - client_id - client_secret - tenant_id + - type: object + title: M365 Static Credentials + properties: + client_id: + type: string + description: The Azure application (client) ID for authentication + in Azure AD. + client_secret: + type: string + description: The client secret associated with the application + (client) ID, providing secure access. + tenant_id: + type: string + description: The Azure tenant ID, representing the directory + where the application is registered. + user: + type: email + description: User microsoft email address. + encrypted_password: + type: string + description: User encrypted password. + required: + - client_id + - client_secret + - tenant_id + - user + - encrypted_password - type: object title: GCP Static Credentials properties: @@ -9939,6 +10064,33 @@ components: - client_id - client_secret - tenant_id + - type: object + title: M365 Static Credentials + properties: + client_id: + type: string + description: The Azure application (client) ID for authentication + in Azure AD. + client_secret: + type: string + description: The client secret associated with the application + (client) ID, providing secure access. + tenant_id: + type: string + description: The Azure tenant ID, representing the directory where + the application is registered. + user: + type: email + description: User microsoft email address. + encrypted_password: + type: string + description: User encrypted password. + required: + - client_id + - client_secret + - tenant_id + - user + - encrypted_password - type: object title: GCP Static Credentials properties: diff --git a/api/src/backend/api/tests/test_utils.py b/api/src/backend/api/tests/test_utils.py index 02a97249c6..0777267484 100644 --- a/api/src/backend/api/tests/test_utils.py +++ b/api/src/backend/api/tests/test_utils.py @@ -19,6 +19,7 @@ from prowler.providers.aws.aws_provider import AwsProvider from prowler.providers.azure.azure_provider import AzureProvider from prowler.providers.gcp.gcp_provider import GcpProvider from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider +from prowler.providers.m365.m365_provider import M365Provider class TestMergeDicts: @@ -104,6 +105,7 @@ class TestReturnProwlerProvider: (Provider.ProviderChoices.GCP.value, GcpProvider), (Provider.ProviderChoices.AZURE.value, AzureProvider), (Provider.ProviderChoices.KUBERNETES.value, KubernetesProvider), + (Provider.ProviderChoices.M365.value, M365Provider), ], ) def test_return_prowler_provider(self, provider_type, expected_provider): @@ -176,6 +178,10 @@ class TestGetProwlerProviderKwargs: Provider.ProviderChoices.KUBERNETES.value, {"context": "provider_uid"}, ), + ( + Provider.ProviderChoices.M365.value, + {}, + ), ], ) def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs): diff --git a/api/src/backend/api/utils.py b/api/src/backend/api/utils.py index 31d009dba5..63581c266e 100644 --- a/api/src/backend/api/utils.py +++ b/api/src/backend/api/utils.py @@ -11,6 +11,7 @@ from prowler.providers.azure.azure_provider import AzureProvider from prowler.providers.common.models import Connection from prowler.providers.gcp.gcp_provider import GcpProvider from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider +from prowler.providers.m365.m365_provider import M365Provider class CustomOAuth2Client(OAuth2Client): @@ -51,14 +52,14 @@ def merge_dicts(default_dict: dict, replacement_dict: dict) -> dict: def return_prowler_provider( provider: Provider, -) -> [AwsProvider | AzureProvider | GcpProvider | KubernetesProvider]: +) -> [AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider]: """Return the Prowler provider class based on the given provider type. Args: provider (Provider): The provider object containing the provider type and associated secrets. Returns: - AwsProvider | AzureProvider | GcpProvider | KubernetesProvider: The corresponding provider class. + AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider: The corresponding provider class. Raises: ValueError: If the provider type specified in `provider.provider` is not supported. @@ -72,6 +73,8 @@ def return_prowler_provider( prowler_provider = AzureProvider case Provider.ProviderChoices.KUBERNETES.value: prowler_provider = KubernetesProvider + case Provider.ProviderChoices.M365.value: + prowler_provider = M365Provider case _: raise ValueError(f"Provider type {provider.provider} not supported") return prowler_provider @@ -104,15 +107,15 @@ def get_prowler_provider_kwargs(provider: Provider) -> dict: def initialize_prowler_provider( provider: Provider, -) -> AwsProvider | AzureProvider | GcpProvider | KubernetesProvider: +) -> AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider: """Initialize a Prowler provider instance based on the given provider type. Args: provider (Provider): The provider object containing the provider type and associated secrets. Returns: - AwsProvider | AzureProvider | GcpProvider | KubernetesProvider: An instance of the corresponding provider class - (`AwsProvider`, `AzureProvider`, `GcpProvider`, or `KubernetesProvider`) initialized with the + AwsProvider | AzureProvider | GcpProvider | KubernetesProvider | M365Provider: An instance of the corresponding provider class + (`AwsProvider`, `AzureProvider`, `GcpProvider`, `KubernetesProvider` or `M365Provider`) initialized with the provider's secrets. """ prowler_provider = return_prowler_provider(provider) @@ -130,10 +133,12 @@ def prowler_provider_connection_test(provider: Provider) -> Connection: Connection: A connection object representing the result of the connection test for the specified provider. """ prowler_provider = return_prowler_provider(provider) + try: prowler_provider_kwargs = provider.secret.secret except Provider.secret.RelatedObjectDoesNotExist as secret_error: return Connection(is_connected=False, error=secret_error) + return prowler_provider.test_connection( **prowler_provider_kwargs, provider_id=provider.uid, raise_on_exception=False ) diff --git a/api/src/backend/api/v1/serializer_utils/providers.py b/api/src/backend/api/v1/serializer_utils/providers.py new file mode 100644 index 0000000000..231e5dc1bb --- /dev/null +++ b/api/src/backend/api/v1/serializer_utils/providers.py @@ -0,0 +1,172 @@ +from drf_spectacular.utils import extend_schema_field +from rest_framework_json_api import serializers + + +@extend_schema_field( + { + "oneOf": [ + { + "type": "object", + "title": "AWS Static Credentials", + "properties": { + "aws_access_key_id": { + "type": "string", + "description": "The AWS access key ID. Required for environments where no IAM role is being " + "assumed and direct AWS access is needed.", + }, + "aws_secret_access_key": { + "type": "string", + "description": "The AWS secret access key. Must accompany 'aws_access_key_id' to authorize " + "access to AWS resources.", + }, + "aws_session_token": { + "type": "string", + "description": "The session token associated with temporary credentials. Only needed for " + "session-based or temporary AWS access.", + }, + }, + "required": ["aws_access_key_id", "aws_secret_access_key"], + }, + { + "type": "object", + "title": "AWS Assume Role", + "properties": { + "role_arn": { + "type": "string", + "description": "The Amazon Resource Name (ARN) of the role to assume. Required for AWS role " + "assumption.", + }, + "external_id": { + "type": "string", + "description": "An identifier to enhance security for role assumption.", + }, + "aws_access_key_id": { + "type": "string", + "description": "The AWS access key ID. Only required if the environment lacks pre-configured " + "AWS credentials.", + }, + "aws_secret_access_key": { + "type": "string", + "description": "The AWS secret access key. Required if 'aws_access_key_id' is provided or if " + "no AWS credentials are pre-configured.", + }, + "aws_session_token": { + "type": "string", + "description": "The session token for temporary credentials, if applicable.", + }, + "session_duration": { + "type": "integer", + "minimum": 900, + "maximum": 43200, + "default": 3600, + "description": "The duration (in seconds) for the role session.", + }, + "role_session_name": { + "type": "string", + "description": "An identifier for the role session, useful for tracking sessions in AWS logs. " + "The regex used to validate this parameter is a string of characters consisting of " + "upper- and lower-case alphanumeric characters with no spaces. You can also include " + "underscores or any of the following characters: =,.@-\n\n" + "Examples:\n" + "- MySession123\n" + "- User_Session-1\n" + "- Test.Session@2", + "pattern": "^[a-zA-Z0-9=,.@_-]+$", + }, + }, + "required": ["role_arn", "external_id"], + }, + { + "type": "object", + "title": "Azure Static Credentials", + "properties": { + "client_id": { + "type": "string", + "description": "The Azure application (client) ID for authentication in Azure AD.", + }, + "client_secret": { + "type": "string", + "description": "The client secret associated with the application (client) ID, providing " + "secure access.", + }, + "tenant_id": { + "type": "string", + "description": "The Azure tenant ID, representing the directory where the application is " + "registered.", + }, + }, + "required": ["client_id", "client_secret", "tenant_id"], + }, + { + "type": "object", + "title": "M365 Static Credentials", + "properties": { + "client_id": { + "type": "string", + "description": "The Azure application (client) ID for authentication in Azure AD.", + }, + "client_secret": { + "type": "string", + "description": "The client secret associated with the application (client) ID, providing " + "secure access.", + }, + "tenant_id": { + "type": "string", + "description": "The Azure tenant ID, representing the directory where the application is " + "registered.", + }, + "user": { + "type": "email", + "description": "User microsoft email address.", + }, + "encrypted_password": { + "type": "string", + "description": "User encrypted password.", + }, + }, + "required": [ + "client_id", + "client_secret", + "tenant_id", + "user", + "encrypted_password", + ], + }, + { + "type": "object", + "title": "GCP Static Credentials", + "properties": { + "client_id": { + "type": "string", + "description": "The client ID from Google Cloud, used to identify the application for GCP " + "access.", + }, + "client_secret": { + "type": "string", + "description": "The client secret associated with the GCP client ID, required for secure " + "access.", + }, + "refresh_token": { + "type": "string", + "description": "A refresh token that allows the application to obtain new access tokens for " + "extended use.", + }, + }, + "required": ["client_id", "client_secret", "refresh_token"], + }, + { + "type": "object", + "title": "Kubernetes Static Credentials", + "properties": { + "kubeconfig_content": { + "type": "string", + "description": "The content of the Kubernetes kubeconfig file, encoded as a string.", + } + }, + "required": ["kubeconfig_content"], + }, + ] + } +) +class ProviderSecretField(serializers.JSONField): + pass diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 96fe46eb85..920384ba65 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -42,6 +42,7 @@ from api.v1.serializer_utils.integrations import ( IntegrationCredentialField, S3ConfigSerializer, ) +from api.v1.serializer_utils.providers import ProviderSecretField # Tokens @@ -1141,6 +1142,8 @@ class BaseWriteProviderSecretSerializer(BaseWriteSerializer): serializer = GCPProviderSecret(data=secret) elif provider_type == Provider.ProviderChoices.KUBERNETES.value: serializer = KubernetesProviderSecret(data=secret) + elif provider_type == Provider.ProviderChoices.M365.value: + serializer = M365ProviderSecret(data=secret) else: raise serializers.ValidationError( {"provider": f"Provider type not supported {provider_type}"} @@ -1180,6 +1183,17 @@ class AzureProviderSecret(serializers.Serializer): resource_name = "provider-secrets" +class M365ProviderSecret(serializers.Serializer): + client_id = serializers.CharField() + client_secret = serializers.CharField() + tenant_id = serializers.CharField() + user = serializers.EmailField() + encrypted_password = serializers.CharField() + + class Meta: + resource_name = "provider-secrets" + + class GCPProviderSecret(serializers.Serializer): client_id = serializers.CharField() client_secret = serializers.CharField() @@ -1211,141 +1225,6 @@ class AWSRoleAssumptionProviderSecret(serializers.Serializer): resource_name = "provider-secrets" -@extend_schema_field( - { - "oneOf": [ - { - "type": "object", - "title": "AWS Static Credentials", - "properties": { - "aws_access_key_id": { - "type": "string", - "description": "The AWS access key ID. Required for environments where no IAM role is being " - "assumed and direct AWS access is needed.", - }, - "aws_secret_access_key": { - "type": "string", - "description": "The AWS secret access key. Must accompany 'aws_access_key_id' to authorize " - "access to AWS resources.", - }, - "aws_session_token": { - "type": "string", - "description": "The session token associated with temporary credentials. Only needed for " - "session-based or temporary AWS access.", - }, - }, - "required": ["aws_access_key_id", "aws_secret_access_key"], - }, - { - "type": "object", - "title": "AWS Assume Role", - "properties": { - "role_arn": { - "type": "string", - "description": "The Amazon Resource Name (ARN) of the role to assume. Required for AWS role " - "assumption.", - }, - "external_id": { - "type": "string", - "description": "An identifier to enhance security for role assumption.", - }, - "aws_access_key_id": { - "type": "string", - "description": "The AWS access key ID. Only required if the environment lacks pre-configured " - "AWS credentials.", - }, - "aws_secret_access_key": { - "type": "string", - "description": "The AWS secret access key. Required if 'aws_access_key_id' is provided or if " - "no AWS credentials are pre-configured.", - }, - "aws_session_token": { - "type": "string", - "description": "The session token for temporary credentials, if applicable.", - }, - "session_duration": { - "type": "integer", - "minimum": 900, - "maximum": 43200, - "default": 3600, - "description": "The duration (in seconds) for the role session.", - }, - "role_session_name": { - "type": "string", - "description": "An identifier for the role session, useful for tracking sessions in AWS logs. " - "The regex used to validate this parameter is a string of characters consisting of " - "upper- and lower-case alphanumeric characters with no spaces. You can also include " - "underscores or any of the following characters: =,.@-\n\n" - "Examples:\n" - "- MySession123\n" - "- User_Session-1\n" - "- Test.Session@2", - "pattern": "^[a-zA-Z0-9=,.@_-]+$", - }, - }, - "required": ["role_arn", "external_id"], - }, - { - "type": "object", - "title": "Azure Static Credentials", - "properties": { - "client_id": { - "type": "string", - "description": "The Azure application (client) ID for authentication in Azure AD.", - }, - "client_secret": { - "type": "string", - "description": "The client secret associated with the application (client) ID, providing " - "secure access.", - }, - "tenant_id": { - "type": "string", - "description": "The Azure tenant ID, representing the directory where the application is " - "registered.", - }, - }, - "required": ["client_id", "client_secret", "tenant_id"], - }, - { - "type": "object", - "title": "GCP Static Credentials", - "properties": { - "client_id": { - "type": "string", - "description": "The client ID from Google Cloud, used to identify the application for GCP " - "access.", - }, - "client_secret": { - "type": "string", - "description": "The client secret associated with the GCP client ID, required for secure " - "access.", - }, - "refresh_token": { - "type": "string", - "description": "A refresh token that allows the application to obtain new access tokens for " - "extended use.", - }, - }, - "required": ["client_id", "client_secret", "refresh_token"], - }, - { - "type": "object", - "title": "Kubernetes Static Credentials", - "properties": { - "kubeconfig_content": { - "type": "string", - "description": "The content of the Kubernetes kubeconfig file, encoded as a string.", - } - }, - "required": ["kubeconfig_content"], - }, - ] - } -) -class ProviderSecretField(serializers.JSONField): - pass - - class ProviderSecretSerializer(RLSSerializer): """ Serializer for the ProviderSecret model. diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index e8dd81ac29..606078b558 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -247,7 +247,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.6.0" + spectacular_settings.VERSION = "1.7.0" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." ) diff --git a/poetry.lock b/poetry.lock index 96e4b10349..96465562a4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,100 +14,105 @@ files = [ [[package]] name = "aiohappyeyeballs" -version = "2.4.4" +version = "2.6.1" description = "Happy Eyeballs for asyncio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, - {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, ] [[package]] name = "aiohttp" -version = "3.11.11" +version = "3.11.18" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a60804bff28662cbcf340a4d61598891f12eea3a66af48ecfdc975ceec21e3c8"}, - {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b4fa1cb5f270fb3eab079536b764ad740bb749ce69a94d4ec30ceee1b5940d5"}, - {file = "aiohttp-3.11.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:731468f555656767cda219ab42e033355fe48c85fbe3ba83a349631541715ba2"}, - {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb23d8bb86282b342481cad4370ea0853a39e4a32a0042bb52ca6bdde132df43"}, - {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f047569d655f81cb70ea5be942ee5d4421b6219c3f05d131f64088c73bb0917f"}, - {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd7659baae9ccf94ae5fe8bfaa2c7bc2e94d24611528395ce88d009107e00c6d"}, - {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af01e42ad87ae24932138f154105e88da13ce7d202a6de93fafdafb2883a00ef"}, - {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5854be2f3e5a729800bac57a8d76af464e160f19676ab6aea74bde18ad19d438"}, - {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6526e5fb4e14f4bbf30411216780c9967c20c5a55f2f51d3abd6de68320cc2f3"}, - {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85992ee30a31835fc482468637b3e5bd085fa8fe9392ba0bdcbdc1ef5e9e3c55"}, - {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:88a12ad8ccf325a8a5ed80e6d7c3bdc247d66175afedbe104ee2aaca72960d8e"}, - {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0a6d3fbf2232e3a08c41eca81ae4f1dff3d8f1a30bae415ebe0af2d2458b8a33"}, - {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84a585799c58b795573c7fa9b84c455adf3e1d72f19a2bf498b54a95ae0d194c"}, - {file = "aiohttp-3.11.11-cp310-cp310-win32.whl", hash = "sha256:bfde76a8f430cf5c5584553adf9926534352251d379dcb266ad2b93c54a29745"}, - {file = "aiohttp-3.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0fd82b8e9c383af11d2b26f27a478640b6b83d669440c0a71481f7c865a51da9"}, - {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76"}, - {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538"}, - {file = "aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204"}, - {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9"}, - {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03"}, - {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287"}, - {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e"}, - {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665"}, - {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b"}, - {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34"}, - {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d"}, - {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2"}, - {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773"}, - {file = "aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62"}, - {file = "aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac"}, - {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886"}, - {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2"}, - {file = "aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c"}, - {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a"}, - {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231"}, - {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e"}, - {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8"}, - {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8"}, - {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c"}, - {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab"}, - {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da"}, - {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853"}, - {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e"}, - {file = "aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600"}, - {file = "aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d"}, - {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9"}, - {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194"}, - {file = "aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f"}, - {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104"}, - {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff"}, - {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3"}, - {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1"}, - {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4"}, - {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d"}, - {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87"}, - {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2"}, - {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12"}, - {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5"}, - {file = "aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d"}, - {file = "aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99"}, - {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3e23419d832d969f659c208557de4a123e30a10d26e1e14b73431d3c13444c2e"}, - {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21fef42317cf02e05d3b09c028712e1d73a9606f02467fd803f7c1f39cc59add"}, - {file = "aiohttp-3.11.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1f21bb8d0235fc10c09ce1d11ffbd40fc50d3f08a89e4cf3a0c503dc2562247a"}, - {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1642eceeaa5ab6c9b6dfeaaa626ae314d808188ab23ae196a34c9d97efb68350"}, - {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2170816e34e10f2fd120f603e951630f8a112e1be3b60963a1f159f5699059a6"}, - {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8be8508d110d93061197fd2d6a74f7401f73b6d12f8822bbcd6d74f2b55d71b1"}, - {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4eed954b161e6b9b65f6be446ed448ed3921763cc432053ceb606f89d793927e"}, - {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6c9af134da4bc9b3bd3e6a70072509f295d10ee60c697826225b60b9959acdd"}, - {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44167fc6a763d534a6908bdb2592269b4bf30a03239bcb1654781adf5e49caf1"}, - {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:479b8c6ebd12aedfe64563b85920525d05d394b85f166b7873c8bde6da612f9c"}, - {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:10b4ff0ad793d98605958089fabfa350e8e62bd5d40aa65cdc69d6785859f94e"}, - {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b540bd67cfb54e6f0865ceccd9979687210d7ed1a1cc8c01f8e67e2f1e883d28"}, - {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dac54e8ce2ed83b1f6b1a54005c87dfed139cf3f777fdc8afc76e7841101226"}, - {file = "aiohttp-3.11.11-cp39-cp39-win32.whl", hash = "sha256:568c1236b2fde93b7720f95a890741854c1200fba4a3471ff48b2934d2d93fd3"}, - {file = "aiohttp-3.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:943a8b052e54dfd6439fd7989f67fc6a7f2138d0a2cf0a7de5f18aa4fe7eb3b1"}, - {file = "aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96264854fedbea933a9ca4b7e0c745728f01380691687b7365d18d9e977179c4"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9602044ff047043430452bc3a2089743fa85da829e6fc9ee0025351d66c332b6"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5691dc38750fcb96a33ceef89642f139aa315c8a193bbd42a0c33476fd4a1609"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554c918ec43f8480b47a5ca758e10e793bd7410b83701676a4782672d670da55"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a4076a2b3ba5b004b8cffca6afe18a3b2c5c9ef679b4d1e9859cf76295f8d4f"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:767a97e6900edd11c762be96d82d13a1d7c4fc4b329f054e88b57cdc21fded94"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ddc9337a0fb0e727785ad4f41163cc314376e82b31846d3835673786420ef1"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f414f37b244f2a97e79b98d48c5ff0789a0b4b4609b17d64fa81771ad780e415"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fdb239f47328581e2ec7744ab5911f97afb10752332a6dd3d98e14e429e1a9e7"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2c50bad73ed629cc326cc0f75aed8ecfb013f88c5af116f33df556ed47143eb"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a8d8f20c39d3fa84d1c28cdb97f3111387e48209e224408e75f29c6f8e0861d"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:106032eaf9e62fd6bc6578c8b9e6dc4f5ed9a5c1c7fb2231010a1b4304393421"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b491e42183e8fcc9901d8dcd8ae644ff785590f1727f76ca86e731c61bfe6643"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad8c745ff9460a16b710e58e06a9dec11ebc0d8f4dd82091cefb579844d69868"}, + {file = "aiohttp-3.11.18-cp310-cp310-win32.whl", hash = "sha256:8e57da93e24303a883146510a434f0faf2f1e7e659f3041abc4e3fb3f6702a9f"}, + {file = "aiohttp-3.11.18-cp310-cp310-win_amd64.whl", hash = "sha256:cc93a4121d87d9f12739fc8fab0a95f78444e571ed63e40bfc78cd5abe700ac9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:427fdc56ccb6901ff8088544bde47084845ea81591deb16f957897f0f0ba1be9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c828b6d23b984255b85b9b04a5b963a74278b7356a7de84fda5e3b76866597b"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c2eaa145bb36b33af1ff2860820ba0589e165be4ab63a49aebfd0981c173b66"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d518ce32179f7e2096bf4e3e8438cf445f05fedd597f252de9f54c728574756"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0700055a6e05c2f4711011a44364020d7a10fbbcd02fbf3e30e8f7e7fddc8717"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bd1cde83e4684324e6ee19adfc25fd649d04078179890be7b29f76b501de8e4"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73b8870fe1c9a201b8c0d12c94fe781b918664766728783241a79e0468427e4f"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25557982dd36b9e32c0a3357f30804e80790ec2c4d20ac6bcc598533e04c6361"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e889c9df381a2433802991288a61e5a19ceb4f61bd14f5c9fa165655dcb1fd1"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9ea345fda05bae217b6cce2acf3682ce3b13d0d16dd47d0de7080e5e21362421"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f26545b9940c4b46f0a9388fd04ee3ad7064c4017b5a334dd450f616396590e"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3a621d85e85dccabd700294494d7179ed1590b6d07a35709bb9bd608c7f5dd1d"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c23fd8d08eb9c2af3faeedc8c56e134acdaf36e2117ee059d7defa655130e5f"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9e6b0e519067caa4fd7fb72e3e8002d16a68e84e62e7291092a5433763dc0dd"}, + {file = "aiohttp-3.11.18-cp311-cp311-win32.whl", hash = "sha256:122f3e739f6607e5e4c6a2f8562a6f476192a682a52bda8b4c6d4254e1138f4d"}, + {file = "aiohttp-3.11.18-cp311-cp311-win_amd64.whl", hash = "sha256:e6f3c0a3a1e73e88af384b2e8a0b9f4fb73245afd47589df2afcab6b638fa0e6"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63d71eceb9cad35d47d71f78edac41fcd01ff10cacaa64e473d1aec13fa02df2"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d1929da615840969929e8878d7951b31afe0bac883d84418f92e5755d7b49508"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0aebeb2392f19b184e3fdd9e651b0e39cd0f195cdb93328bd124a1d455cd0e"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3849ead845e8444f7331c284132ab314b4dac43bfae1e3cf350906d4fff4620f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e8452ad6b2863709f8b3d615955aa0807bc093c34b8e25b3b52097fe421cb7f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b8d2b42073611c860a37f718b3d61ae8b4c2b124b2e776e2c10619d920350ec"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fbf91f6a0ac317c0a07eb328a1384941872f6761f2e6f7208b63c4cc0a7ff6"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ff5625413fec55216da5eaa011cf6b0a2ed67a565914a212a51aa3755b0009"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f33a92a2fde08e8c6b0c61815521324fc1612f397abf96eed86b8e31618fdb4"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:11d5391946605f445ddafda5eab11caf310f90cdda1fd99865564e3164f5cff9"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3cc314245deb311364884e44242e00c18b5896e4fe6d5f942e7ad7e4cb640adb"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f421843b0f70740772228b9e8093289924359d306530bcd3926f39acbe1adda"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e220e7562467dc8d589e31c1acd13438d82c03d7f385c9cd41a3f6d1d15807c1"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab2ef72f8605046115bc9aa8e9d14fd49086d405855f40b79ed9e5c1f9f4faea"}, + {file = "aiohttp-3.11.18-cp312-cp312-win32.whl", hash = "sha256:12a62691eb5aac58d65200c7ae94d73e8a65c331c3a86a2e9670927e94339ee8"}, + {file = "aiohttp-3.11.18-cp312-cp312-win_amd64.whl", hash = "sha256:364329f319c499128fd5cd2d1c31c44f234c58f9b96cc57f743d16ec4f3238c8"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:474215ec618974054cf5dc465497ae9708543cbfc312c65212325d4212525811"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ced70adf03920d4e67c373fd692123e34d3ac81dfa1c27e45904a628567d804"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d9f6c0152f8d71361905aaf9ed979259537981f47ad099c8b3d81e0319814bd"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a35197013ed929c0aed5c9096de1fc5a9d336914d73ab3f9df14741668c0616c"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:540b8a1f3a424f1af63e0af2d2853a759242a1769f9f1ab053996a392bd70118"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9e6710ebebfce2ba21cee6d91e7452d1125100f41b906fb5af3da8c78b764c1"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8af2ef3b4b652ff109f98087242e2ab974b2b2b496304063585e3d78de0b000"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28c3f975e5ae3dbcbe95b7e3dcd30e51da561a0a0f2cfbcdea30fc1308d72137"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c28875e316c7b4c3e745172d882d8a5c835b11018e33432d281211af35794a93"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:13cd38515568ae230e1ef6919e2e33da5d0f46862943fcda74e7e915096815f3"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0e2a92101efb9f4c2942252c69c63ddb26d20f46f540c239ccfa5af865197bb8"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e6d3e32b8753c8d45ac550b11a1090dd66d110d4ef805ffe60fa61495360b3b2"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ea4cf2488156e0f281f93cc2fd365025efcba3e2d217cbe3df2840f8c73db261"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d4df95ad522c53f2b9ebc07f12ccd2cb15550941e11a5bbc5ddca2ca56316d7"}, + {file = "aiohttp-3.11.18-cp313-cp313-win32.whl", hash = "sha256:cdd1bbaf1e61f0d94aced116d6e95fe25942f7a5f42382195fd9501089db5d78"}, + {file = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl", hash = "sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:469ac32375d9a716da49817cd26f1916ec787fc82b151c1c832f58420e6d3533"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cec21dd68924179258ae14af9f5418c1ebdbba60b98c667815891293902e5e0"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b426495fb9140e75719b3ae70a5e8dd3a79def0ae3c6c27e012fc59f16544a4a"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2f41203e2808616292db5d7170cccf0c9f9c982d02544443c7eb0296e8b0c7"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc0ae0a5e9939e423e065a3e5b00b24b8379f1db46046d7ab71753dfc7dd0e1"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7cdd3f7d1df43200e1c80f1aed86bb36033bf65e3c7cf46a2b97a253ef8798"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5199be2a2f01ffdfa8c3a6f5981205242986b9e63eb8ae03fd18f736e4840721"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ccec9e72660b10f8e283e91aa0295975c7bd85c204011d9f5eb69310555cf30"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1596ebf17e42e293cbacc7a24c3e0dc0f8f755b40aff0402cb74c1ff6baec1d3"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eab7b040a8a873020113ba814b7db7fa935235e4cbaf8f3da17671baa1024863"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5d61df4a05476ff891cff0030329fee4088d40e4dc9b013fac01bc3c745542c2"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:46533e6792e1410f9801d09fd40cbbff3f3518d1b501d6c3c5b218f427f6ff08"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c1b90407ced992331dd6d4f1355819ea1c274cc1ee4d5b7046c6761f9ec11829"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a2fd04ae4971b914e54fe459dd7edbbd3f2ba875d69e057d5e3c8e8cac094935"}, + {file = "aiohttp-3.11.18-cp39-cp39-win32.whl", hash = "sha256:b2f317d1678002eee6fe85670039fb34a757972284614638f82b903a03feacdc"}, + {file = "aiohttp-3.11.18-cp39-cp39-win_amd64.whl", hash = "sha256:5e7007b8d1d09bce37b54111f593d173691c530b80f27c6493b928dabed9e6ef"}, + {file = "aiohttp-3.11.18.tar.gz", hash = "sha256:ae856e1138612b7e412db63b7708735cff4d38d0399f6a5435d3dac2669f558a"}, ] [package.dependencies] @@ -168,14 +173,14 @@ files = [ [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, + {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, ] [package.dependencies] @@ -185,20 +190,20 @@ sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] +doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] name = "astroid" -version = "3.3.8" +version = "3.3.9" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.9.0" groups = ["dev"] files = [ - {file = "astroid-3.3.8-py3-none-any.whl", hash = "sha256:187ccc0c248bfbba564826c26f070494f7bc964fd286b6d9fff4420e55de828c"}, - {file = "astroid-3.3.8.tar.gz", hash = "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b"}, + {file = "astroid-3.3.9-py3-none-any.whl", hash = "sha256:d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248"}, + {file = "astroid-3.3.9.tar.gz", hash = "sha256:622cc8e3048684aa42c820d9d218978021c3c3d174fb03a9f0d615921744f550"}, ] [package.dependencies] @@ -219,34 +224,34 @@ files = [ [[package]] name = "attrs" -version = "24.3.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, - {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "authlib" -version = "1.4.0" +version = "1.5.2" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "Authlib-1.4.0-py2.py3-none-any.whl", hash = "sha256:4bb20b978c8b636222b549317c1815e1fe62234fc1c5efe8855d84aebf3a74e3"}, - {file = "authlib-1.4.0.tar.gz", hash = "sha256:1c1e6608b5ed3624aeeee136ca7f8c120d6f51f731aa152b153d54741840e1f2"}, + {file = "authlib-1.5.2-py2.py3-none-any.whl", hash = "sha256:8804dd4402ac5e4a0435ac49e0b6e19e395357cfa632a3f624dcb4f6df13b4b1"}, + {file = "authlib-1.5.2.tar.gz", hash = "sha256:fe85ec7e50c5f86f1e2603518bb3b4f632985eb4a355e52256530790e326c512"}, ] [package.dependencies] @@ -254,21 +259,21 @@ cryptography = "*" [[package]] name = "aws-sam-translator" -version = "1.94.0" +version = "1.97.0" description = "AWS SAM Translator is a library that transform SAM templates into AWS CloudFormation templates" optional = false python-versions = "!=4.0,<=4.0,>=3.8" groups = ["dev"] files = [ - {file = "aws_sam_translator-1.94.0-py3-none-any.whl", hash = "sha256:100e33eeffcfa81f7c45cadeb0ee29596ce829f6b4d2745140f04fa19a41f539"}, - {file = "aws_sam_translator-1.94.0.tar.gz", hash = "sha256:8ec258d9f7ece72ef91c81f4edb45a2db064c16844b6afac90c575893beaa391"}, + {file = "aws_sam_translator-1.97.0-py3-none-any.whl", hash = "sha256:305701ab49eb546fd720b3682e99cadcd43539f4ddb8395ea03c90c9e14d3325"}, + {file = "aws_sam_translator-1.97.0.tar.gz", hash = "sha256:6f7ec94de0a9b220dd1f1a0bf7e2df95dd44a85592301ee830744da2f209b7e6"}, ] [package.dependencies] boto3 = ">=1.19.5,<2.dev0" jsonschema = ">=3.2,<5" pydantic = ">=1.8,<1.10.15 || >1.10.15,<1.10.17 || >1.10.17,<3" -typing-extensions = ">=4.4" +typing_extensions = ">=4.4" [package.extras] dev = ["black (==24.3.0)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.dev0)", "coverage (>=5.3,<8)", "dateparser (>=1.1,<2.0)", "mypy (>=1.3.0,<1.4.0)", "parameterized (>=0.7,<1.0)", "pytest (>=6.2,<8)", "pytest-cov (>=2.10,<5)", "pytest-env (>=0.6,<1)", "pytest-rerunfailures (>=9.1,<12)", "pytest-xdist (>=2.5,<4)", "pyyaml (>=6.0,<7.0)", "requests (>=2.28,<3.0)", "ruamel.yaml (==0.17.21)", "ruff (>=0.4.5,<0.5.0)", "tenacity (>=8.0,<9.0)", "types-PyYAML (>=6.0,<7.0)", "types-jsonschema (>=3.2,<4.0)"] @@ -315,14 +320,14 @@ files = [ [[package]] name = "azure-core" -version = "1.32.0" +version = "1.33.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, - {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, + {file = "azure_core-1.33.0-py3-none-any.whl", hash = "sha256:9b5b6d0223a1d38c37500e6971118c1e0f13f54951e6893968b38910bc9cda8f"}, + {file = "azure_core-1.33.0.tar.gz", hash = "sha256:f367aa07b5e3005fec2c1e184b882b0b039910733907d001c20fb08ebb8c0eb9"}, ] [package.dependencies] @@ -332,6 +337,7 @@ typing-extensions = ">=4.6.0" [package.extras] aio = ["aiohttp (>=3.0)"] +tracing = ["opentelemetry-api (>=1.26,<2.0)"] [[package]] name = "azure-identity" @@ -707,18 +713,18 @@ aio = ["azure-core[aio] (>=1.30.0)"] [[package]] name = "babel" -version = "2.16.0" +version = "2.17.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" groups = ["docs"] files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, + {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, + {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, ] [package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "bandit" @@ -849,26 +855,26 @@ crt = ["awscrt (==0.22.0)"] [[package]] name = "cachetools" -version = "5.5.0" +version = "5.5.2" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, + {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, + {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, ] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main", "dev", "docs"] files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -954,18 +960,18 @@ pycparser = "*" [[package]] name = "cfn-lint" -version = "1.22.5" +version = "1.34.1" description = "Checks CloudFormation templates for practices and behaviour that could potentially be improved" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "cfn_lint-1.22.5-py3-none-any.whl", hash = "sha256:18309e59cc03ff18b02676688df7eb1a17f5276da3776f31946fc0d9aa9b8fe7"}, - {file = "cfn_lint-1.22.5.tar.gz", hash = "sha256:8b4f55e283143e99d8d331627637226c291cecfb936606f7aab2d940e71e566d"}, + {file = "cfn_lint-1.34.1-py3-none-any.whl", hash = "sha256:2c21a908fa5d9b0c1caac2081c10261eaae7fce88364e4edc607717892f36d68"}, + {file = "cfn_lint-1.34.1.tar.gz", hash = "sha256:58f4352c370a710b72b389eda0acd6762e62f926e534d2eb1609d5326ded4bed"}, ] [package.dependencies] -aws-sam-translator = ">=1.94.0" +aws-sam-translator = ">=1.97.0" jsonpatch = "*" networkx = ">=2.4,<4" pyyaml = ">5.4" @@ -1349,21 +1355,21 @@ files = [ [[package]] name = "deprecated" -version = "1.2.15" +version = "1.2.18" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" groups = ["main"] files = [ - {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, - {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, + {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, + {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, ] [package.dependencies] wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "setuptools ; python_version >= \"3.12\"", "sphinx (<2)", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "detect-secrets" @@ -1387,14 +1393,14 @@ word-list = ["pyahocorasick"] [[package]] name = "dill" -version = "0.3.9" +version = "0.4.0" description = "serialize all of Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, - {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, + {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, + {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, ] [package.extras] @@ -1601,104 +1607,116 @@ python-dateutil = ">=2.7" [[package]] name = "frozenlist" -version = "1.5.0" +version = "1.6.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, - {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, - {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, - {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, - {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, - {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, - {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, - {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, - {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, - {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, - {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, - {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, - {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, - {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, - {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e6e558ea1e47fd6fa8ac9ccdad403e5dd5ecc6ed8dda94343056fa4277d5c65e"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4b3cd7334a4bbc0c472164f3744562cb72d05002cc6fcf58adb104630bbc352"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9799257237d0479736e2b4c01ff26b5c7f7694ac9692a426cb717f3dc02fff9b"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a7bb0fe1f7a70fb5c6f497dc32619db7d2cdd53164af30ade2f34673f8b1fc"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:36d2fc099229f1e4237f563b2a3e0ff7ccebc3999f729067ce4e64a97a7f2869"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f27a9f9a86dcf00708be82359db8de86b80d029814e6693259befe82bb58a106"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75ecee69073312951244f11b8627e3700ec2bfe07ed24e3a685a5979f0412d24"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2c7d5aa19714b1b01a0f515d078a629e445e667b9da869a3cd0e6fe7dec78bd"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69bbd454f0fb23b51cadc9bdba616c9678e4114b6f9fa372d462ff2ed9323ec8"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7daa508e75613809c7a57136dec4871a21bca3080b3a8fc347c50b187df4f00c"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:89ffdb799154fd4d7b85c56d5fa9d9ad48946619e0eb95755723fffa11022d75"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:920b6bd77d209931e4c263223381d63f76828bec574440f29eb497cf3394c249"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d3ceb265249fb401702fce3792e6b44c1166b9319737d21495d3611028d95769"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52021b528f1571f98a7d4258c58aa8d4b1a96d4f01d00d51f1089f2e0323cb02"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f2ca7810b809ed0f1917293050163c7654cefc57a49f337d5cd9de717b8fad3"}, + {file = "frozenlist-1.6.0-cp310-cp310-win32.whl", hash = "sha256:0e6f8653acb82e15e5443dba415fb62a8732b68fe09936bb6d388c725b57f812"}, + {file = "frozenlist-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a39819a5a3e84304cd286e3dc62a549fe60985415851b3337b6f5cc91907f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae8337990e7a45683548ffb2fee1af2f1ed08169284cd829cdd9a7fa7470530d"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c952f69dd524558694818a461855f35d36cc7f5c0adddce37e962c85d06eac0"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f5fef13136c4e2dee91bfb9a44e236fff78fc2cd9f838eddfc470c3d7d90afe"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:716bbba09611b4663ecbb7cd022f640759af8259e12a6ca939c0a6acd49eedba"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b8c4dc422c1a3ffc550b465090e53b0bf4839047f3e436a34172ac67c45d595"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b11534872256e1666116f6587a1592ef395a98b54476addb5e8d352925cb5d4a"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c6eceb88aaf7221f75be6ab498dc622a151f5f88d536661af3ffc486245a626"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62c828a5b195570eb4b37369fcbbd58e96c905768d53a44d13044355647838ff"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c6bd2c6399920c9622362ce95a7d74e7f9af9bfec05fff91b8ce4b9647845a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49ba23817781e22fcbd45fd9ff2b9b8cdb7b16a42a4851ab8025cae7b22e96d0"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:431ef6937ae0f853143e2ca67d6da76c083e8b1fe3df0e96f3802fd37626e606"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9d124b38b3c299ca68433597ee26b7819209cb8a3a9ea761dfe9db3a04bba584"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:118e97556306402e2b010da1ef21ea70cb6d6122e580da64c056b96f524fbd6a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb3b309f1d4086b5533cf7bbcf3f956f0ae6469664522f1bde4feed26fba60f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54dece0d21dce4fdb188a1ffc555926adf1d1c516e493c2914d7c370e454bc9e"}, + {file = "frozenlist-1.6.0-cp311-cp311-win32.whl", hash = "sha256:654e4ba1d0b2154ca2f096bed27461cf6160bc7f504a7f9a9ef447c293caf860"}, + {file = "frozenlist-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e911391bffdb806001002c1f860787542f45916c3baf764264a52765d5a5603"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770"}, + {file = "frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc"}, + {file = "frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d7fb014fe0fbfee3efd6a94fc635aeaa68e5e1720fe9e57357f2e2c6e1a647e"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01bcaa305a0fdad12745502bfd16a1c75b14558dabae226852f9159364573117"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b314faa3051a6d45da196a2c495e922f987dc848e967d8cfeaee8a0328b1cd4"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da62fecac21a3ee10463d153549d8db87549a5e77eefb8c91ac84bb42bb1e4e3"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1eb89bf3454e2132e046f9599fbcf0a4483ed43b40f545551a39316d0201cd1"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18689b40cb3936acd971f663ccb8e2589c45db5e2c5f07e0ec6207664029a9c"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e67ddb0749ed066b1a03fba812e2dcae791dd50e5da03be50b6a14d0c1a9ee45"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc5e64626e6682638d6e44398c9baf1d6ce6bc236d40b4b57255c9d3f9761f1f"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:437cfd39564744ae32ad5929e55b18ebd88817f9180e4cc05e7d53b75f79ce85"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62dd7df78e74d924952e2feb7357d826af8d2f307557a779d14ddf94d7311be8"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a66781d7e4cddcbbcfd64de3d41a61d6bdde370fc2e38623f30b2bd539e84a9f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:482fe06e9a3fffbcd41950f9d890034b4a54395c60b5e61fae875d37a699813f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e4f9373c500dfc02feea39f7a56e4f543e670212102cc2eeb51d3a99c7ffbde6"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e69bb81de06827147b7bfbaeb284d85219fa92d9f097e32cc73675f279d70188"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7613d9977d2ab4a9141dde4a149f4357e4065949674c5649f920fec86ecb393e"}, + {file = "frozenlist-1.6.0-cp313-cp313-win32.whl", hash = "sha256:4def87ef6d90429f777c9d9de3961679abf938cb6b7b63d4a7eb8a268babfce4"}, + {file = "frozenlist-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:37a8a52c3dfff01515e9bbbee0e6063181362f9de3db2ccf9bc96189b557cbfd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:46138f5a0773d064ff663d273b309b696293d7a7c00a0994c5c13a5078134b64"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f88bc0a2b9c2a835cb888b32246c27cdab5740059fb3688852bf91e915399b91"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:777704c1d7655b802c7850255639672e90e81ad6fa42b99ce5ed3fbf45e338dd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ef8d41764c7de0dcdaf64f733a27352248493a85a80661f3c678acd27e31f2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:da5cb36623f2b846fb25009d9d9215322318ff1c63403075f812b3b2876c8506"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbb56587a16cf0fb8acd19e90ff9924979ac1431baea8681712716a8337577b0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6154c3ba59cda3f954c6333025369e42c3acd0c6e8b6ce31eb5c5b8116c07e0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e8246877afa3f1ae5c979fe85f567d220f86a50dc6c493b9b7d8191181ae01e"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0f6cce16306d2e117cf9db71ab3a9e8878a28176aeaf0dbe35248d97b28d0c"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1b8e8cd8032ba266f91136d7105706ad57770f3522eac4a111d77ac126a25a9b"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e2ada1d8515d3ea5378c018a5f6d14b4994d4036591a52ceaf1a1549dec8e1ad"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:cdb2c7f071e4026c19a3e32b93a09e59b12000751fc9b0b7758da899e657d215"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:03572933a1969a6d6ab509d509e5af82ef80d4a5d4e1e9f2e1cdd22c77a3f4d2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:77effc978947548b676c54bbd6a08992759ea6f410d4987d69feea9cd0919911"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a2bda8be77660ad4089caf2223fdbd6db1858462c4b85b67fbfa22102021e497"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:a4d96dc5bcdbd834ec6b0f91027817214216b5b30316494d2b1aebffb87c534f"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e18036cb4caa17ea151fd5f3d70be9d354c99eb8cf817a3ccde8a7873b074348"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:536a1236065c29980c15c7229fbb830dedf809708c10e159b8136534233545f0"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ed5e3a4462ff25ca84fb09e0fada8ea267df98a450340ead4c91b44857267d70"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e19c0fc9f4f030fcae43b4cdec9e8ab83ffe30ec10c79a4a43a04d1af6c5e1ad"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c608f833897501dac548585312d73a7dca028bf3b8688f0d712b7acfaf7fb3"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0dbae96c225d584f834b8d3cc688825911960f003a85cb0fd20b6e5512468c42"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:625170a91dd7261a1d1c2a0c1a353c9e55d21cd67d0852185a5fef86587e6f5f"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1db8b2fc7ee8a940b547a14c10e56560ad3ea6499dc6875c354e2335812f739d"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4da6fc43048b648275a220e3a61c33b7fff65d11bdd6dcb9d9c145ff708b804c"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef8e7e8f2f3820c5f175d70fdd199b79e417acf6c72c5d0aa8f63c9f721646f"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa733d123cc78245e9bb15f29b44ed9e5780dc6867cfc4e544717b91f980af3b"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ba7f8d97152b61f22d7f59491a781ba9b177dd9f318486c5fbc52cde2db12189"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:56a0b8dd6d0d3d971c91f1df75e824986667ccce91e20dca2023683814344791"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5c9e89bf19ca148efcc9e3c44fd4c09d5af85c8a7dd3dbd0da1cb83425ef4983"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1330f0a4376587face7637dfd245380a57fe21ae8f9d360c1c2ef8746c4195fa"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2187248203b59625566cac53572ec8c2647a140ee2738b4e36772930377a533c"}, + {file = "frozenlist-1.6.0-cp39-cp39-win32.whl", hash = "sha256:2b8cf4cfea847d6c12af06091561a89740f1f67f331c3fa8623391905e878530"}, + {file = "frozenlist-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:1255d5d64328c5a0d066ecb0f02034d086537925f1f04b50b1ae60d37afbf572"}, + {file = "frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191"}, + {file = "frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68"}, ] [[package]] @@ -1755,22 +1773,22 @@ test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3. [[package]] name = "google-api-core" -version = "2.24.0" +version = "2.24.2" description = "Google API client core library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9"}, - {file = "google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf"}, + {file = "google_api_core-2.24.2-py3-none-any.whl", hash = "sha256:810a63ac95f3c441b7c0e43d344e372887f62ce9071ba972eacf32672e072de9"}, + {file = "google_api_core-2.24.2.tar.gz", hash = "sha256:81718493daf06d96d6bc76a91c23874dbf2fac0adbbf542831b805ee6e974696"}, ] [package.dependencies] -google-auth = ">=2.14.1,<3.0.dev0" -googleapis-common-protos = ">=1.56.2,<2.0.dev0" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" -requests = ">=2.18.0,<3.0.0.dev0" +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.56.2,<2.0.0" +proto-plus = ">=1.22.3,<2.0.0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" +requests = ">=2.18.0,<3.0.0" [package.extras] async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.dev0)"] @@ -1799,14 +1817,14 @@ uritemplate = ">=3.0.1,<5" [[package]] name = "google-auth" -version = "2.37.0" +version = "2.39.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0"}, - {file = "google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00"}, + {file = "google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2"}, + {file = "google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7"}, ] [package.dependencies] @@ -1815,12 +1833,14 @@ pyasn1-modules = ">=0.2.1" rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] enterprise-cert = ["cryptography", "pyopenssl"] -pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] [[package]] name = "google-auth-httplib2" @@ -1840,21 +1860,21 @@ httplib2 = ">=0.19.0" [[package]] name = "googleapis-common-protos" -version = "1.66.0" +version = "1.70.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, - {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, + {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"}, + {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"}, ] [package.dependencies] -protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "grapheme" @@ -1872,14 +1892,14 @@ test = ["pytest", "sphinx", "sphinx-autobuild", "twine", "wheel"] [[package]] name = "graphql-core" -version = "3.2.5" +version = "3.2.6" description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." optional = false python-versions = "<4,>=3.6" groups = ["dev"] files = [ - {file = "graphql_core-3.2.5-py3-none-any.whl", hash = "sha256:2f150d5096448aa4f8ab26268567bbfeef823769893b39c1a2e1409590939c8a"}, - {file = "graphql_core-3.2.5.tar.gz", hash = "sha256:e671b90ed653c808715645e3998b7ab67d382d55467b7e2978549111bbabf8d5"}, + {file = "graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"}, + {file = "graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab"}, ] [package.dependencies] @@ -1899,42 +1919,42 @@ files = [ [[package]] name = "h2" -version = "4.1.0" -description = "HTTP/2 State-Machine based protocol implementation" +version = "4.2.0" +description = "Pure-Python HTTP/2 protocol implementation" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, - {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, + {file = "h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0"}, + {file = "h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f"}, ] [package.dependencies] -hpack = ">=4.0,<5" -hyperframe = ">=6.0,<7" +hpack = ">=4.1,<5" +hyperframe = ">=6.1,<7" [[package]] name = "hpack" -version = "4.0.0" -description = "Pure-Python HPACK header compression" +version = "4.1.0" +description = "Pure-Python HPACK header encoding" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, - {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, + {file = "hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"}, + {file = "hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca"}, ] [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.8" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, + {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, ] [package.dependencies] @@ -1990,14 +2010,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "hyperframe" -version = "6.0.1" -description = "HTTP/2 framing layer for Python" +version = "6.1.0" +description = "Pure-Python HTTP/2 framing" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, - {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, + {file = "hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"}, + {file = "hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08"}, ] [[package]] @@ -2017,14 +2037,14 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "8.5.0" +version = "8.6.1" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev", "docs"] files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, ] markers = {dev = "python_version < \"3.10\"", docs = "python_version < \"3.10\""} @@ -2037,19 +2057,19 @@ cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -2066,18 +2086,19 @@ files = [ [[package]] name = "isort" -version = "5.13.2" +version = "6.0.1" description = "A Python utility / library to sort Python imports." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" groups = ["dev"] files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, + {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, + {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, ] [package.extras] -colors = ["colorama (>=0.4.6)"] +colors = ["colorama"] +plugins = ["setuptools"] [[package]] name = "itsdangerous" @@ -2123,14 +2144,14 @@ files = [ [[package]] name = "joserfc" -version = "1.0.2" +version = "1.0.4" description = "The ultimate Python library for JOSE RFCs, including JWS, JWE, JWK, JWA, JWT" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "joserfc-1.0.2-py3-none-any.whl", hash = "sha256:8d3e0253b0b24aeaf049d7bf7a847040dd6462de24cefd0c14abfc8b353f9619"}, - {file = "joserfc-1.0.2.tar.gz", hash = "sha256:f3c4efa35a62fc100097e4bec2584f5fd21b878eee3eb5324bc9b37d2969b2a4"}, + {file = "joserfc-1.0.4-py3-none-any.whl", hash = "sha256:ecf3a5999f89d3a663485ab7c4f633541586d6f44e664ee760197299f39ed51b"}, + {file = "joserfc-1.0.4.tar.gz", hash = "sha256:dc3fc216cfcfc952d4c0d4b06c759a04711af0b667e5973adc47dbb1ba784127"}, ] [package.dependencies] @@ -2206,20 +2227,20 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-path" -version = "0.3.3" +version = "0.3.4" description = "JSONSchema Spec with object-oriented paths" optional = false python-versions = "<4.0.0,>=3.8.0" groups = ["dev"] files = [ - {file = "jsonschema_path-0.3.3-py3-none-any.whl", hash = "sha256:203aff257f8038cd3c67be614fe6b2001043408cb1b4e36576bc4921e09d83c4"}, - {file = "jsonschema_path-0.3.3.tar.gz", hash = "sha256:f02e5481a4288ec062f8e68c808569e427d905bedfecb7f2e4c69ef77957c382"}, + {file = "jsonschema_path-0.3.4-py3-none-any.whl", hash = "sha256:f502191fdc2b22050f9a81c9237be9d27145b9001c55842bece5e94e382e52f8"}, + {file = "jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001"}, ] [package.dependencies] pathable = ">=0.4.1,<0.5.0" PyYAML = ">=5.1" -referencing = ">=0.28.0,<0.36.0" +referencing = "<0.37.0" requests = ">=2.31.0,<3.0.0" [[package]] @@ -2267,68 +2288,45 @@ adal = ["adal (>=1.0.2)"] [[package]] name = "lazy-object-proxy" -version = "1.10.0" +version = "1.11.0" description = "A fast and thorough lazy object proxy." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"}, - {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"}, + {file = "lazy_object_proxy-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:132bc8a34f2f2d662a851acfd1b93df769992ed1b81e2b1fda7db3e73b0d5a18"}, + {file = "lazy_object_proxy-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:01261a3afd8621a1accb5682df2593dc7ec7d21d38f411011a5712dcd418fbed"}, + {file = "lazy_object_proxy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:090935756cc041e191f22f4f9c7fd4fe9a454717067adf5b1bbd2ce3046b556e"}, + {file = "lazy_object_proxy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:76ec715017f06410f57df442c1a8d66e6b5f7035077785b129817f5ae58810a4"}, + {file = "lazy_object_proxy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a9f39098e93a63618a79eef2889ae3cf0605f676cd4797fdfd49fcd7ddc318b"}, + {file = "lazy_object_proxy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ee13f67f4fcd044ef27bfccb1c93d39c100046fec1fad6e9a1fcdfd17492aeb3"}, + {file = "lazy_object_proxy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4c84eafd8dd15ea16f7d580758bc5c2ce1f752faec877bb2b1f9f827c329cd"}, + {file = "lazy_object_proxy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:d2503427bda552d3aefcac92f81d9e7ca631e680a2268cbe62cd6a58de6409b7"}, + {file = "lazy_object_proxy-1.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0613116156801ab3fccb9e2b05ed83b08ea08c2517fdc6c6bc0d4697a1a376e3"}, + {file = "lazy_object_proxy-1.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bb03c507d96b65f617a6337dedd604399d35face2cdf01526b913fb50c4cb6e8"}, + {file = "lazy_object_proxy-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28c174db37946f94b97a97b579932ff88f07b8d73a46b6b93322b9ac06794a3b"}, + {file = "lazy_object_proxy-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:d662f0669e27704495ff1f647070eb8816931231c44e583f4d0701b7adf6272f"}, + {file = "lazy_object_proxy-1.11.0-py3-none-any.whl", hash = "sha256:a56a5093d433341ff7da0e89f9b486031ccd222ec8e52ec84d0ec1cdc819674b"}, + {file = "lazy_object_proxy-1.11.0.tar.gz", hash = "sha256:18874411864c9fbbbaa47f9fc1dd7aea754c86cfde21278ef427639d1dd78e9c"}, ] [[package]] name = "markdown" -version = "3.7" +version = "3.8" description = "Python implementation of John Gruber's Markdown." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, - {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, + {file = "markdown-3.8-py3-none-any.whl", hash = "sha256:794a929b79c5af141ef5ab0f2f642d0f7b1872981250230e72682346f7cc90dc"}, + {file = "markdown-3.8.tar.gz", hash = "sha256:7df81e63f0df5c4b24b7d156eb81e4690595239b7d70937d0409f1b0de319c6f"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] [[package]] @@ -2429,14 +2427,14 @@ files = [ [[package]] name = "marshmallow" -version = "3.25.1" +version = "3.26.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "marshmallow-3.25.1-py3-none-any.whl", hash = "sha256:ec5d00d873ce473b7f2ffcb7104286a376c354cab0c2fa12f5573dab03e87210"}, - {file = "marshmallow-3.25.1.tar.gz", hash = "sha256:f4debda3bb11153d81ac34b0d582bf23053055ee11e791b54b4b35493468040a"}, + {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, + {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, ] [package.dependencies] @@ -2502,20 +2500,20 @@ std-uritemplate = ">=2.0.0" [[package]] name = "microsoft-kiota-authentication-azure" -version = "1.9.1" +version = "1.9.2" description = "Core abstractions for kiota generated libraries in Python" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_authentication_azure-1.9.1-py3-none-any.whl", hash = "sha256:3a3030b01e0cbf007736ec6548ac483742e04ad0d20979b49e293a683f839fc6"}, - {file = "microsoft_kiota_authentication_azure-1.9.1.tar.gz", hash = "sha256:8ba31b1ecf78777128daf3191c7ecd28bfc2d10d0fe80260dd5c07a9ccd5d7f5"}, + {file = "microsoft_kiota_authentication_azure-1.9.2-py3-none-any.whl", hash = "sha256:56840f8b15df8aedfd143fb2deb7cc7fae4ac0bafb1a50546b7313a7b3ab4ca0"}, + {file = "microsoft_kiota_authentication_azure-1.9.2.tar.gz", hash = "sha256:171045f522a93d9340fbddc4cabb218f14f1d9d289e82e535b3d9291986c3d5a"}, ] [package.dependencies] aiohttp = ">=3.8.0" azure-core = ">=1.21.1" -microsoft-kiota-abstractions = ">=1.9.1,<1.10.0" +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" opentelemetry-api = ">=1.27.0" opentelemetry-sdk = ">=1.27.0" @@ -2539,63 +2537,63 @@ opentelemetry-sdk = ">=1.27.0" [[package]] name = "microsoft-kiota-serialization-form" -version = "1.9.1" +version = "1.9.2" description = "Core abstractions for kiota generated libraries in Python" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_serialization_form-1.9.1-py3-none-any.whl", hash = "sha256:d86c0dc08b51288f2851a265dde729b200998bca1dd1681bbebcb27cd274ba34"}, - {file = "microsoft_kiota_serialization_form-1.9.1.tar.gz", hash = "sha256:58b81eca5e0ad66bcbd6a4b65ba91e6255d3510f4c4f576fb4f5e83ca9a310c3"}, + {file = "microsoft_kiota_serialization_form-1.9.2-py3-none-any.whl", hash = "sha256:7b997efb2c8750b1d4fbc00878ba2a3e6e1df3fcefc8815226c90fcc9c54f218"}, + {file = "microsoft_kiota_serialization_form-1.9.2.tar.gz", hash = "sha256:badfbe65d8ec3369bd58b01022d13ef590edf14babeef94188efe3f4ec24fe41"}, ] [package.dependencies] -microsoft-kiota-abstractions = ">=1.9.1,<1.10.0" +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" [[package]] name = "microsoft-kiota-serialization-json" -version = "1.9.1" +version = "1.9.2" description = "Core abstractions for kiota generated libraries in Python" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_serialization_json-1.9.1-py3-none-any.whl", hash = "sha256:ab752bf642a77266713bac3942a4c547dde60b917f674a9ab63261490fecf841"}, - {file = "microsoft_kiota_serialization_json-1.9.1.tar.gz", hash = "sha256:0039458b885875daf246f1e8c0296551695e0ec70f3e4689b00b270ce923c0cc"}, + {file = "microsoft_kiota_serialization_json-1.9.2-py3-none-any.whl", hash = "sha256:8f4ecf485607fff3df5ce8fa9b9c957bc7f4bff1658b183703e180af753098e3"}, + {file = "microsoft_kiota_serialization_json-1.9.2.tar.gz", hash = "sha256:19f7beb69c67b2cb77ca96f77824ee78a693929e20237bb5476ea54f69118bf1"}, ] [package.dependencies] -microsoft-kiota-abstractions = ">=1.9.1,<1.10.0" +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" [[package]] name = "microsoft-kiota-serialization-multipart" -version = "1.9.1" +version = "1.9.2" description = "Core abstractions for kiota generated libraries in Python" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_serialization_multipart-1.9.1-py3-none-any.whl", hash = "sha256:1ee69d8e3b2c0d24431b85fc1628534f97dcafed45dcb6bb3f0143824ce8a665"}, - {file = "microsoft_kiota_serialization_multipart-1.9.1.tar.gz", hash = "sha256:288790a486aad33aac0a7329f05b8851e9be82f50cc9a8f19fe6f267a4f2b183"}, + {file = "microsoft_kiota_serialization_multipart-1.9.2-py3-none-any.whl", hash = "sha256:641ad374046f1c7adff90d110bdc68d77418adb1e479a716f4ffea3647f0ead6"}, + {file = "microsoft_kiota_serialization_multipart-1.9.2.tar.gz", hash = "sha256:b1851409205668d83f5c7a35a8b6fca974b341985b4a92841e95aaec93b7ca0a"}, ] [package.dependencies] -microsoft-kiota-abstractions = ">=1.9.1,<1.10.0" +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" [[package]] name = "microsoft-kiota-serialization-text" -version = "1.9.1" +version = "1.9.2" description = "Core abstractions for kiota generated libraries in Python" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "microsoft_kiota_serialization_text-1.9.1-py3-none-any.whl", hash = "sha256:021fbfad887f7525f9e1c8bbe225d0aa1b25befe54357ae0f739f47576d946ff"}, - {file = "microsoft_kiota_serialization_text-1.9.1.tar.gz", hash = "sha256:b4b1f61c2388edd704ab33a1792f92f3507db9648d389197a625e152b52743ab"}, + {file = "microsoft_kiota_serialization_text-1.9.2-py3-none-any.whl", hash = "sha256:6e63129ea29eb9b976f4ed56fc6595d204e29fc309958b639299e9f9f4e5edb4"}, + {file = "microsoft_kiota_serialization_text-1.9.2.tar.gz", hash = "sha256:4289508ebac0cefdc4fa21c545051769a9409913972355ccda9116b647f978f2"}, ] [package.dependencies] -microsoft-kiota-abstractions = ">=1.9.1,<1.10.0" +microsoft-kiota-abstractions = ">=1.9.2,<1.10.0" [[package]] name = "mkdocs" @@ -2804,18 +2802,18 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msal" -version = "1.31.1" +version = "1.32.0" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "msal-1.31.1-py3-none-any.whl", hash = "sha256:29d9882de247e96db01386496d59f29035e5e841bcac892e6d7bf4390bf6bd17"}, - {file = "msal-1.31.1.tar.gz", hash = "sha256:11b5e6a3f802ffd3a72107203e20c4eac6ef53401961b880af2835b723d80578"}, + {file = "msal-1.32.0-py3-none-any.whl", hash = "sha256:9dbac5384a10bbbf4dae5c7ea0d707d14e087b92c5aa4954b3feaa2d1aa0bcb7"}, + {file = "msal-1.32.0.tar.gz", hash = "sha256:5445fe3af1da6be484991a7ab32eaa82461dc2347de105b76af92c610c3335c2"}, ] [package.dependencies] -cryptography = ">=2.5,<46" +cryptography = ">=2.5,<47" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" @@ -2824,30 +2822,32 @@ broker = ["pymsalruntime (>=0.14,<0.18) ; python_version >= \"3.6\" and platform [[package]] name = "msal-extensions" -version = "1.2.0" +version = "1.3.1" description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d"}, - {file = "msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef"}, + {file = "msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"}, + {file = "msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4"}, ] [package.dependencies] msal = ">=1.29,<2" -portalocker = ">=1.4,<3" + +[package.extras] +portalocker = ["portalocker (>=1.4,<4)"] [[package]] name = "msgraph-core" -version = "1.3.2" +version = "1.3.3" description = "Core component of the Microsoft Graph Python SDK" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "msgraph_core-1.3.2-py3-none-any.whl", hash = "sha256:96d3d1ad1d2bc3d1d5eb76599e18cb699ccc78781b3492702b2f23ec8f22ae6e"}, - {file = "msgraph_core-1.3.2.tar.gz", hash = "sha256:d23964bfb20f636874ef875a984f5ab9e48fc4854f1530c6e4a617b84d59777d"}, + {file = "msgraph_core-1.3.3-py3-none-any.whl", hash = "sha256:9dbbc0c88e174c1d5da1c17d286965d6b26ebaf24996c7af64a39e2069006cf6"}, + {file = "msgraph_core-1.3.3.tar.gz", hash = "sha256:a3226b08b4cf9b6dbb16b868be21d5f82d8ee514ae8e46d9f0cad896159ef8d3"}, ] [package.dependencies] @@ -2906,104 +2906,116 @@ async = ["aiodns ; python_version >= \"3.5\"", "aiohttp (>=3.0) ; python_version [[package]] name = "multidict" -version = "6.1.0" +version = "6.4.3" description = "multidict implementation" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32a998bd8a64ca48616eac5a8c1cc4fa38fb244a3facf2eeb14abe186e0f6cc5"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a54ec568f1fc7f3c313c2f3b16e5db346bf3660e1309746e7fccbbfded856188"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a7be07e5df178430621c716a63151165684d3e9958f2bbfcb644246162007ab7"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b128dbf1c939674a50dd0b28f12c244d90e5015e751a4f339a96c54f7275e291"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9cb19dfd83d35b6ff24a4022376ea6e45a2beba8ef3f0836b8a4b288b6ad685"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cf62f8e447ea2c1395afa289b332e49e13d07435369b6f4e41f887db65b40bf"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:909f7d43ff8f13d1adccb6a397094adc369d4da794407f8dd592c51cf0eae4b1"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bb8f8302fbc7122033df959e25777b0b7659b1fd6bcb9cb6bed76b5de67afef"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:224b79471b4f21169ea25ebc37ed6f058040c578e50ade532e2066562597b8a9"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a7bd27f7ab3204f16967a6f899b3e8e9eb3362c0ab91f2ee659e0345445e0078"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:99592bd3162e9c664671fd14e578a33bfdba487ea64bcb41d281286d3c870ad7"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a62d78a1c9072949018cdb05d3c533924ef8ac9bcb06cbf96f6d14772c5cd451"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ccdde001578347e877ca4f629450973c510e88e8865d5aefbcb89b852ccc666"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:eccb67b0e78aa2e38a04c5ecc13bab325a43e5159a181a9d1a6723db913cbb3c"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b6fcf6054fc4114a27aa865f8840ef3d675f9316e81868e0ad5866184a6cba5"}, + {file = "multidict-6.4.3-cp310-cp310-win32.whl", hash = "sha256:f92c7f62d59373cd93bc9969d2da9b4b21f78283b1379ba012f7ee8127b3152e"}, + {file = "multidict-6.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:b57e28dbc031d13916b946719f213c494a517b442d7b48b29443e79610acd887"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6f19170197cc29baccd33ccc5b5d6a331058796485857cf34f7635aa25fb0cd"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2882bf27037eb687e49591690e5d491e677272964f9ec7bc2abbe09108bdfb8"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbf226ac85f7d6b6b9ba77db4ec0704fde88463dc17717aec78ec3c8546c70ad"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e329114f82ad4b9dd291bef614ea8971ec119ecd0f54795109976de75c9a852"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1f4e0334d7a555c63f5c8952c57ab6f1c7b4f8c7f3442df689fc9f03df315c08"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:740915eb776617b57142ce0bb13b7596933496e2f798d3d15a20614adf30d229"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255dac25134d2b141c944b59a0d2f7211ca12a6d4779f7586a98b4b03ea80508"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e8535bd4d741039b5aad4285ecd9b902ef9e224711f0b6afda6e38d7ac02c7"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c433a33be000dd968f5750722eaa0991037be0be4a9d453eba121774985bc8"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4eb33b0bdc50acd538f45041f5f19945a1f32b909b76d7b117c0c25d8063df56"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:75482f43465edefd8a5d72724887ccdcd0c83778ded8f0cb1e0594bf71736cc0"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce5b3082e86aee80b3925ab4928198450d8e5b6466e11501fe03ad2191c6d777"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e413152e3212c4d39f82cf83c6f91be44bec9ddea950ce17af87fbf4e32ca6b2"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8aac2eeff69b71f229a405c0a4b61b54bade8e10163bc7b44fcd257949620618"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab583ac203af1d09034be41458feeab7863c0635c650a16f15771e1386abf2d7"}, + {file = "multidict-6.4.3-cp311-cp311-win32.whl", hash = "sha256:1b2019317726f41e81154df636a897de1bfe9228c3724a433894e44cd2512378"}, + {file = "multidict-6.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:43173924fa93c7486402217fab99b60baf78d33806af299c56133a3755f69589"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f1c2f58f08b36f8475f3ec6f5aeb95270921d418bf18f90dffd6be5c7b0e676"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:26ae9ad364fc61b936fb7bf4c9d8bd53f3a5b4417142cd0be5c509d6f767e2f1"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:659318c6c8a85f6ecfc06b4e57529e5a78dfdd697260cc81f683492ad7e9435a"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1eb72c741fd24d5a28242ce72bb61bc91f8451877131fa3fe930edb195f7054"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cd06d88cb7398252284ee75c8db8e680aa0d321451132d0dba12bc995f0adcc"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4543d8dc6470a82fde92b035a92529317191ce993533c3c0c68f56811164ed07"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30a3ebdc068c27e9d6081fca0e2c33fdf132ecea703a72ea216b81a66860adde"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b038f10e23f277153f86f95c777ba1958bcd5993194fda26a1d06fae98b2f00c"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c605a2b2dc14282b580454b9b5d14ebe0668381a3a26d0ac39daa0ca115eb2ae"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bd2b875f4ca2bb527fe23e318ddd509b7df163407b0fb717df229041c6df5d3"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c2e98c840c9c8e65c0e04b40c6c5066c8632678cd50c8721fdbcd2e09f21a507"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66eb80dd0ab36dbd559635e62fba3083a48a252633164857a1d1684f14326427"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c23831bdee0a2a3cf21be057b5e5326292f60472fb6c6f86392bbf0de70ba731"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1535cec6443bfd80d028052e9d17ba6ff8a5a3534c51d285ba56c18af97e9713"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b73e7227681f85d19dec46e5b881827cd354aabe46049e1a61d2f9aaa4e285a"}, + {file = "multidict-6.4.3-cp312-cp312-win32.whl", hash = "sha256:8eac0c49df91b88bf91f818e0a24c1c46f3622978e2c27035bfdca98e0e18124"}, + {file = "multidict-6.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:11990b5c757d956cd1db7cb140be50a63216af32cd6506329c2c59d732d802db"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a76534263d03ae0cfa721fea40fd2b5b9d17a6f85e98025931d41dc49504474"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:805031c2f599eee62ac579843555ed1ce389ae00c7e9f74c2a1b45e0564a88dd"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c56c179839d5dcf51d565132185409d1d5dd8e614ba501eb79023a6cab25576b"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c64f4ddb3886dd8ab71b68a7431ad4aa01a8fa5be5b11543b29674f29ca0ba3"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3002a856367c0b41cad6784f5b8d3ab008eda194ed7864aaa58f65312e2abcac"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d75e621e7d887d539d6e1d789f0c64271c250276c333480a9e1de089611f790"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:995015cf4a3c0d72cbf453b10a999b92c5629eaf3a0c3e1efb4b5c1f602253bb"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b0fabae7939d09d7d16a711468c385272fa1b9b7fb0d37e51143585d8e72e0"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61ed4d82f8a1e67eb9eb04f8587970d78fe7cddb4e4d6230b77eda23d27938f9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:062428944a8dc69df9fdc5d5fc6279421e5f9c75a9ee3f586f274ba7b05ab3c8"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b90e27b4674e6c405ad6c64e515a505c6d113b832df52fdacb6b1ffd1fa9a1d1"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7d50d4abf6729921e9613d98344b74241572b751c6b37feed75fb0c37bd5a817"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:43fe10524fb0a0514be3954be53258e61d87341008ce4914f8e8b92bee6f875d"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:236966ca6c472ea4e2d3f02f6673ebfd36ba3f23159c323f5a496869bc8e47c9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:422a5ec315018e606473ba1f5431e064cf8b2a7468019233dcf8082fabad64c8"}, + {file = "multidict-6.4.3-cp313-cp313-win32.whl", hash = "sha256:f901a5aace8e8c25d78960dcc24c870c8d356660d3b49b93a78bf38eb682aac3"}, + {file = "multidict-6.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:1c152c49e42277bc9a2f7b78bd5fa10b13e88d1b0328221e7aef89d5c60a99a5"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:be8751869e28b9c0d368d94f5afcb4234db66fe8496144547b4b6d6a0645cfc6"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d4b31f8a68dccbcd2c0ea04f0e014f1defc6b78f0eb8b35f2265e8716a6df0c"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:032efeab3049e37eef2ff91271884303becc9e54d740b492a93b7e7266e23756"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e78006af1a7c8a8007e4f56629d7252668344442f66982368ac06522445e375"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:daeac9dd30cda8703c417e4fddccd7c4dc0c73421a0b54a7da2713be125846be"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f6f90700881438953eae443a9c6f8a509808bc3b185246992c4233ccee37fea"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f84627997008390dd15762128dcf73c3365f4ec0106739cde6c20a07ed198ec8"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3307b48cd156153b117c0ea54890a3bdbf858a5b296ddd40dc3852e5f16e9b02"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead46b0fa1dcf5af503a46e9f1c2e80b5d95c6011526352fa5f42ea201526124"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1748cb2743bedc339d63eb1bca314061568793acd603a6e37b09a326334c9f44"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:acc9fa606f76fc111b4569348cc23a771cb52c61516dcc6bcef46d612edb483b"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:31469d5832b5885adeb70982e531ce86f8c992334edd2f2254a10fa3182ac504"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ba46b51b6e51b4ef7bfb84b82f5db0dc5e300fb222a8a13b8cd4111898a869cf"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:389cfefb599edf3fcfd5f64c0410da686f90f5f5e2c4d84e14f6797a5a337af4"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:64bc2bbc5fba7b9db5c2c8d750824f41c6994e3882e6d73c903c2afa78d091e4"}, + {file = "multidict-6.4.3-cp313-cp313t-win32.whl", hash = "sha256:0ecdc12ea44bab2807d6b4a7e5eef25109ab1c82a8240d86d3c1fc9f3b72efd5"}, + {file = "multidict-6.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7146a8742ea71b5d7d955bffcef58a9e6e04efba704b52a460134fefd10a8208"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5427a2679e95a642b7f8b0f761e660c845c8e6fe3141cddd6b62005bd133fc21"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:24a8caa26521b9ad09732972927d7b45b66453e6ebd91a3c6a46d811eeb7349b"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6b5a272bc7c36a2cd1b56ddc6bff02e9ce499f9f14ee4a45c45434ef083f2459"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf74dc5e212b8c75165b435c43eb0d5e81b6b300a938a4eb82827119115e840"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9f35de41aec4b323c71f54b0ca461ebf694fb48bec62f65221f52e0017955b39"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae93e0ff43b6f6892999af64097b18561691ffd835e21a8348a441e256592e1f"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e3929269e9d7eff905d6971d8b8c85e7dbc72c18fb99c8eae6fe0a152f2e343"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6214fe1750adc2a1b801a199d64b5a67671bf76ebf24c730b157846d0e90d2"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d79cf5c0c6284e90f72123f4a3e4add52d6c6ebb4a9054e88df15b8d08444c6"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2427370f4a255262928cd14533a70d9738dfacadb7563bc3b7f704cc2360fc4e"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:fbd8d737867912b6c5f99f56782b8cb81f978a97b4437a1c476de90a3e41c9a1"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0ee1bf613c448997f73fc4efb4ecebebb1c02268028dd4f11f011f02300cf1e8"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578568c4ba5f2b8abd956baf8b23790dbfdc953e87d5b110bce343b4a54fc9e7"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a059ad6b80de5b84b9fa02a39400319e62edd39d210b4e4f8c4f1243bdac4752"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dd53893675b729a965088aaadd6a1f326a72b83742b056c1065bdd2e2a42b4df"}, + {file = "multidict-6.4.3-cp39-cp39-win32.whl", hash = "sha256:abcfed2c4c139f25c2355e180bcc077a7cae91eefbb8b3927bb3f836c9586f1f"}, + {file = "multidict-6.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:b1b389ae17296dd739015d5ddb222ee99fd66adeae910de21ac950e00979d897"}, + {file = "multidict-6.4.3-py3-none-any.whl", hash = "sha256:59fe01ee8e2a1e8ceb3f6dbb216b09c8d9f4ef1c22c4fc825d045a147fa2ebc9"}, + {file = "multidict-6.4.3.tar.gz", hash = "sha256:3ada0b058c9f213c5f95ba301f922d402ac234f1111a7d8fd70f1b99f3c281ec"}, ] [package.dependencies] @@ -3027,16 +3039,40 @@ docs = ["sphinx (>=8,<9)", "sphinx-autobuild"] [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] +[[package]] +name = "narwhals" +version = "1.35.0" +description = "Extremely lightweight compatibility layer between dataframe libraries" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "narwhals-1.35.0-py3-none-any.whl", hash = "sha256:7562af132fa3f8aaaf34dc96d7ec95bdca29d1c795e8fcf14e01edf1d32122bc"}, + {file = "narwhals-1.35.0.tar.gz", hash = "sha256:07477d18487fbc940243b69818a177ed7119b737910a8a254fb67688b48a7c96"}, +] + +[package.extras] +cudf = ["cudf (>=24.10.0)"] +dask = ["dask[dataframe] (>=2024.8)"] +duckdb = ["duckdb (>=1.0)"] +ibis = ["ibis-framework (>=6.0.0)", "packaging", "pyarrow-hotfix", "rich"] +modin = ["modin"] +pandas = ["pandas (>=0.25.3)"] +polars = ["polars (>=0.20.3)"] +pyarrow = ["pyarrow (>=11.0.0)"] +pyspark = ["pyspark (>=3.5.0)"] +sqlframe = ["sqlframe (>=3.22.0)"] + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -3056,6 +3092,7 @@ description = "Python package for creating and manipulating graphs and networks" optional = false python-versions = ">=3.9" groups = ["dev"] +markers = "python_version < \"3.10\"" files = [ {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, @@ -3068,6 +3105,27 @@ doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9. extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] +[[package]] +name = "networkx" +version = "3.4.2" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, +] + +[package.extras] +default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "numpy" version = "2.0.2" @@ -3177,63 +3235,63 @@ openapi-schema-validator = ">=0.6.0,<0.7.0" [[package]] name = "opentelemetry-api" -version = "1.29.0" +version = "1.32.1" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_api-1.29.0-py3-none-any.whl", hash = "sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8"}, - {file = "opentelemetry_api-1.29.0.tar.gz", hash = "sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf"}, + {file = "opentelemetry_api-1.32.1-py3-none-any.whl", hash = "sha256:bbd19f14ab9f15f0e85e43e6a958aa4cb1f36870ee62b7fd205783a112012724"}, + {file = "opentelemetry_api-1.32.1.tar.gz", hash = "sha256:a5be71591694a4d9195caf6776b055aa702e964d961051a0715d05f8632c32fb"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=8.5.0" +importlib-metadata = ">=6.0,<8.7.0" [[package]] name = "opentelemetry-sdk" -version = "1.29.0" +version = "1.32.1" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_sdk-1.29.0-py3-none-any.whl", hash = "sha256:173be3b5d3f8f7d671f20ea37056710217959e774e2749d984355d1f9391a30a"}, - {file = "opentelemetry_sdk-1.29.0.tar.gz", hash = "sha256:b0787ce6aade6ab84315302e72bd7a7f2f014b0fb1b7c3295b88afe014ed0643"}, + {file = "opentelemetry_sdk-1.32.1-py3-none-any.whl", hash = "sha256:bba37b70a08038613247bc42beee5a81b0ddca422c7d7f1b097b32bf1c7e2f17"}, + {file = "opentelemetry_sdk-1.32.1.tar.gz", hash = "sha256:8ef373d490961848f525255a42b193430a0637e064dd132fd2a014d94792a092"}, ] [package.dependencies] -opentelemetry-api = "1.29.0" -opentelemetry-semantic-conventions = "0.50b0" +opentelemetry-api = "1.32.1" +opentelemetry-semantic-conventions = "0.53b1" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.50b0" +version = "0.53b1" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "opentelemetry_semantic_conventions-0.50b0-py3-none-any.whl", hash = "sha256:e87efba8fdb67fb38113efea6a349531e75ed7ffc01562f65b802fcecb5e115e"}, - {file = "opentelemetry_semantic_conventions-0.50b0.tar.gz", hash = "sha256:02dc6dbcb62f082de9b877ff19a3f1ffaa3c306300fa53bfac761c4567c83d38"}, + {file = "opentelemetry_semantic_conventions-0.53b1-py3-none-any.whl", hash = "sha256:21df3ed13f035f8f3ea42d07cbebae37020367a53b47f1ebee3b10a381a00208"}, + {file = "opentelemetry_semantic_conventions-0.53b1.tar.gz", hash = "sha256:4c5a6fede9de61211b2e9fc1e02e8acacce882204cd770177342b6a3be682992"}, ] [package.dependencies] deprecated = ">=1.2.6" -opentelemetry-api = "1.29.0" +opentelemetry-api = "1.32.1" [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main", "dev", "docs"] files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -3365,48 +3423,54 @@ files = [ [[package]] name = "pbr" -version = "6.1.0" +version = "6.1.1" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" groups = ["dev"] files = [ - {file = "pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a"}, - {file = "pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24"}, + {file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"}, + {file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"}, ] +[package.dependencies] +setuptools = "*" + [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.3.7" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev", "docs"] files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] [[package]] name = "plotly" -version = "5.24.1" -description = "An open-source, interactive data visualization library for Python" +version = "6.0.1" +description = "An open-source interactive data visualization library for Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089"}, - {file = "plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae"}, + {file = "plotly-6.0.1-py3-none-any.whl", hash = "sha256:4714db20fea57a435692c548a4eb4fae454f7daddf15f8d8ba7e1045681d7768"}, + {file = "plotly-6.0.1.tar.gz", hash = "sha256:dd8400229872b6e3c964b099be699f8d00c489a974f2cfccfad5e8240873366b"}, ] [package.dependencies] +narwhals = ">=1.15.1" packaging = "*" -tenacity = ">=6.2.0" + +[package.extras] +express = ["numpy"] [[package]] name = "pluggy" @@ -3436,155 +3500,149 @@ files = [ {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, ] -[[package]] -name = "portalocker" -version = "2.10.1" -description = "Wraps the portalocker recipe for easy usage" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, - {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, -] - -[package.dependencies] -pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} - -[package.extras] -docs = ["sphinx (>=1.7.1)"] -redis = ["redis"] -tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] - [[package]] name = "propcache" -version = "0.2.1" +version = "0.3.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, - {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, - {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, - {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, - {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, - {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, - {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, - {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, - {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, - {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, - {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, - {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, - {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, + {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, + {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, + {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, + {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, + {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, + {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, + {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, + {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, + {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, + {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, + {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, + {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, + {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, + {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, ] [[package]] name = "proto-plus" -version = "1.25.0" -description = "Beautiful, Pythonic protocol buffers." +version = "1.26.1" +description = "Beautiful, Pythonic protocol buffers" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "proto_plus-1.25.0-py3-none-any.whl", hash = "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961"}, - {file = "proto_plus-1.25.0.tar.gz", hash = "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91"}, + {file = "proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66"}, + {file = "proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012"}, ] [package.dependencies] -protobuf = ">=3.19.0,<6.0.0dev" +protobuf = ">=3.19.0,<7.0.0" [package.extras] testing = ["google-api-core (>=1.31.5)"] [[package]] name = "protobuf" -version = "5.29.3" +version = "6.30.2" description = "" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"}, - {file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"}, - {file = "protobuf-5.29.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e"}, - {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84"}, - {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f"}, - {file = "protobuf-5.29.3-cp38-cp38-win32.whl", hash = "sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252"}, - {file = "protobuf-5.29.3-cp38-cp38-win_amd64.whl", hash = "sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107"}, - {file = "protobuf-5.29.3-cp39-cp39-win32.whl", hash = "sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7"}, - {file = "protobuf-5.29.3-cp39-cp39-win_amd64.whl", hash = "sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da"}, - {file = "protobuf-5.29.3-py3-none-any.whl", hash = "sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f"}, - {file = "protobuf-5.29.3.tar.gz", hash = "sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620"}, + {file = "protobuf-6.30.2-cp310-abi3-win32.whl", hash = "sha256:b12ef7df7b9329886e66404bef5e9ce6a26b54069d7f7436a0853ccdeb91c103"}, + {file = "protobuf-6.30.2-cp310-abi3-win_amd64.whl", hash = "sha256:7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9"}, + {file = "protobuf-6.30.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:0eb523c550a66a09a0c20f86dd554afbf4d32b02af34ae53d93268c1f73bc65b"}, + {file = "protobuf-6.30.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:50f32cc9fd9cb09c783ebc275611b4f19dfdfb68d1ee55d2f0c7fa040df96815"}, + {file = "protobuf-6.30.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4f6c687ae8efae6cf6093389a596548214467778146b7245e886f35e1485315d"}, + {file = "protobuf-6.30.2-cp39-cp39-win32.whl", hash = "sha256:524afedc03b31b15586ca7f64d877a98b184f007180ce25183d1a5cb230ee72b"}, + {file = "protobuf-6.30.2-cp39-cp39-win_amd64.whl", hash = "sha256:acec579c39c88bd8fbbacab1b8052c793efe83a0a5bd99db4a31423a25c0a0e2"}, + {file = "protobuf-6.30.2-py3-none-any.whl", hash = "sha256:ae86b030e69a98e08c77beab574cbcb9fff6d031d57209f574a5aea1445f4b51"}, + {file = "protobuf-6.30.2.tar.gz", hash = "sha256:35c859ae076d8c56054c25b59e5e59638d86545ed6e2b6efac6be0b6ea3ba048"}, ] [[package]] @@ -3663,18 +3721,18 @@ files = [ [[package]] name = "pyasn1-modules" -version = "0.4.1" +version = "0.4.2" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, - {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.7.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycodestyle" @@ -3849,14 +3907,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pymdown-extensions" -version = "10.14" +version = "10.14.3" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" groups = ["docs"] files = [ - {file = "pymdown_extensions-10.14-py3-none-any.whl", hash = "sha256:202481f716cc8250e4be8fce997781ebf7917701b59652458ee47f2401f818b5"}, - {file = "pymdown_extensions-10.14.tar.gz", hash = "sha256:741bd7c4ff961ba40b7528d32284c53bc436b8b1645e8e37c3e57770b8700a34"}, + {file = "pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9"}, + {file = "pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b"}, ] [package.dependencies] @@ -3868,14 +3926,14 @@ extra = ["pygments (>=2.19.1)"] [[package]] name = "pyparsing" -version = "3.2.1" +version = "3.2.3" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, - {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, + {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, + {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, ] [package.extras] @@ -4008,32 +4066,30 @@ files = [ [[package]] name = "pywin32" -version = "308" +version = "310" description = "Python for Window Extensions" optional = false python-versions = "*" -groups = ["main", "dev"] +groups = ["dev"] +markers = "sys_platform == \"win32\"" files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, + {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"}, + {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"}, + {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"}, + {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, ] -markers = {main = "platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} [[package]] name = "pyyaml" @@ -4115,19 +4171,20 @@ pyyaml = "*" [[package]] name = "referencing" -version = "0.35.1" +version = "0.36.2" description = "JSON Referencing + Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, + {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, + {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, ] [package.dependencies] attrs = ">=22.2.0" rpds-py = ">=0.7.0" +typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "regex" @@ -4291,14 +4348,14 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "responses" -version = "0.25.6" +version = "0.25.7" description = "A utility library for mocking out the `requests` Python library." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "responses-0.25.6-py3-none-any.whl", hash = "sha256:9cac8f21e1193bb150ec557875377e41ed56248aed94e4567ed644db564bacf1"}, - {file = "responses-0.25.6.tar.gz", hash = "sha256:eae7ce61a9603004e76c05691e7c389e59652d91e94b419623c12bbfb8e331d8"}, + {file = "responses-0.25.7-py3-none-any.whl", hash = "sha256:92ca17416c90fe6b35921f52179bff29332076bb32694c0df02dcac2c6bc043c"}, + {file = "responses-0.25.7.tar.gz", hash = "sha256:8ebae11405d7a5df79ab6fd54277f6f2bc29b2d002d0dd2d5c632594d1ddcedb"}, ] [package.dependencies] @@ -4341,14 +4398,14 @@ six = "*" [[package]] name = "rich" -version = "13.9.4" +version = "14.0.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" groups = ["dev"] files = [ - {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, - {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, + {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, + {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, ] [package.dependencies] @@ -4361,127 +4418,138 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.22.3" +version = "0.24.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, - {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, - {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, - {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, - {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, - {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, - {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, - {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, - {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, - {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, - {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, - {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, - {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, - {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, - {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, - {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, - {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, - {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, - {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, - {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, - {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, - {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, - {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, - {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, - {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, - {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, - {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, - {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, - {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, - {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, - {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, - {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"}, + {file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc"}, + {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f"}, + {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875"}, + {file = "rpds_py-0.24.0-cp310-cp310-win32.whl", hash = "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07"}, + {file = "rpds_py-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef"}, + {file = "rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae"}, + {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c"}, + {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718"}, + {file = "rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a"}, + {file = "rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205"}, + {file = "rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029"}, + {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91"}, + {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56"}, + {file = "rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30"}, + {file = "rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c"}, + {file = "rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d"}, + {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120"}, + {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9"}, + {file = "rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143"}, + {file = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114"}, + {file = "rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797"}, + {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba"}, + {file = "rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d"}, + {file = "rpds_py-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c"}, + {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149"}, + {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45"}, + {file = "rpds_py-0.24.0-cp39-cp39-win32.whl", hash = "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103"}, + {file = "rpds_py-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc"}, + {file = "rpds_py-0.24.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25"}, + {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796"}, + {file = "rpds_py-0.24.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f"}, + {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"}, ] [[package]] name = "rsa" -version = "4.9" +version = "4.9.1" description = "Pure-Python RSA implementation" optional = false -python-versions = ">=3.6,<4" +python-versions = "<4,>=3.6" groups = ["main"] files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, ] [package.dependencies] @@ -4521,7 +4589,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, @@ -4530,7 +4597,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, @@ -4539,7 +4605,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, @@ -4548,7 +4613,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, @@ -4557,7 +4621,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, @@ -4650,19 +4713,19 @@ files = [ [[package]] name = "setuptools" -version = "75.8.0" +version = "79.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, - {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, + {file = "setuptools-79.0.0-py3-none-any.whl", hash = "sha256:b9ab3a104bedb292323f53797b00864e10e434a3ab3906813a7169e4745b912a"}, + {file = "setuptools-79.0.0.tar.gz", hash = "sha256:9828422e7541213b0aacb6e10bbf9dd8febeaa45a48570e09b6d100e063fc9f9"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] @@ -4753,26 +4816,26 @@ files = [ [[package]] name = "std-uritemplate" -version = "2.0.1" +version = "2.0.3" description = "std-uritemplate implementation for Python" optional = false python-versions = "<4.0,>=3.8" groups = ["main"] files = [ - {file = "std_uritemplate-2.0.1-py3-none-any.whl", hash = "sha256:6405d13f9ff3b8f70e1fa4eaefa373049659e1a61870c4b651441821a3fc984d"}, - {file = "std_uritemplate-2.0.1.tar.gz", hash = "sha256:f4684ae050167e237ed5819423139893e0b5b7f08dc6b7467bba3fdd64608be8"}, + {file = "std_uritemplate-2.0.3-py3-none-any.whl", hash = "sha256:434df26453bf68c6077879fed6609b2c39e2fc73080e74cd157269d5f8abdb3e"}, + {file = "std_uritemplate-2.0.3.tar.gz", hash = "sha256:ad4cb1d671bcf4a3608b3598c687be4b0929867c53a2d69c105989da6a5a2d4c"}, ] [[package]] name = "stevedore" -version = "5.4.0" +version = "5.4.1" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857"}, - {file = "stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d"}, + {file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"}, + {file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"}, ] [package.dependencies] @@ -4811,32 +4874,16 @@ files = [ [package.extras] widechars = ["wcwidth"] -[[package]] -name = "tenacity" -version = "9.0.0" -description = "Retry code until it succeeds" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, - {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, -] - -[package.extras] -doc = ["reno", "sphinx"] -test = ["pytest", "tornado (>=4.5)", "typeguard"] - [[package]] name = "tldextract" -version = "5.1.3" +version = "5.3.0" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75"}, - {file = "tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338"}, + {file = "tldextract-5.3.0-py3-none-any.whl", hash = "sha256:f70f31d10b55c83993f55e91ecb7c5d84532a8972f22ec578ecfbe5ea2292db2"}, + {file = "tldextract-5.3.0.tar.gz", hash = "sha256:b3d2b70a1594a0ecfa6967d57251527d58e00bb5a91a74387baa0d87a0678609"}, ] [package.dependencies] @@ -4906,14 +4953,14 @@ files = [ [[package]] name = "typer" -version = "0.15.1" +version = "0.15.2" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"}, - {file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"}, + {file = "typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc"}, + {file = "typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5"}, ] [package.dependencies] @@ -4924,26 +4971,26 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] [[package]] name = "tzdata" -version = "2024.2" +version = "2025.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main"] files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, ] [[package]] @@ -4996,15 +5043,15 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.3.0" +version = "2.4.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "dev", "docs"] markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, - {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, + {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, + {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, ] [package.extras] @@ -5197,14 +5244,14 @@ files = [ [[package]] name = "xlsxwriter" -version = "3.2.0" +version = "3.2.3" description = "A Python module for creating Excel XLSX files." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "XlsxWriter-3.2.0-py3-none-any.whl", hash = "sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e"}, - {file = "XlsxWriter-3.2.0.tar.gz", hash = "sha256:9977d0c661a72866a61f9f7a809e25ebbb0fb7036baa3b9fe74afcfca6b3cb8c"}, + {file = "XlsxWriter-3.2.3-py3-none-any.whl", hash = "sha256:593f8296e8a91790c6d0378ab08b064f34a642b3feb787cf6738236bd0a4860d"}, + {file = "xlsxwriter-3.2.3.tar.gz", hash = "sha256:ad6fd41bdcf1b885876b1f6b7087560aecc9ae5a9cc2ba97dcac7ab2e210d3d5"}, ] [[package]] @@ -5221,100 +5268,122 @@ files = [ [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1f6670b9ae3daedb325fa55fbe31c22c8228f6e0b513772c2e1c623caa6ab22"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85a231fa250dfa3308f3c7896cc007a47bc76e9e8e8595c20b7426cac4884c62"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a06701b647c9939d7019acdfa7ebbfbb78ba6aa05985bb195ad716ea759a569"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7595498d085becc8fb9203aa314b136ab0516c7abd97e7d74f7bb4eb95042abe"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af5607159085dcdb055d5678fc2d34949bd75ae6ea6b4381e784bbab1c3aa195"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95b50910e496567434cb77a577493c26bce0f31c8a305135f3bda6a2483b8e10"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b594113a301ad537766b4e16a5a6750fcbb1497dcc1bc8a4daae889e6402a634"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:083ce0393ea173cd37834eb84df15b6853b555d20c52703e21fbababa8c129d2"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1a350a652bbbe12f666109fbddfdf049b3ff43696d18c9ab1531fbba1c977a"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fb0caeac4a164aadce342f1597297ec0ce261ec4532bbc5a9ca8da5622f53867"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d88cc43e923f324203f6ec14434fa33b85c06d18d59c167a0637164863b8e995"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e52d6ed9ea8fd3abf4031325dc714aed5afcbfa19ee4a89898d663c9976eb487"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ce360ae48a5e9961d0c730cf891d40698a82804e85f6e74658fb175207a77cb2"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:06d06c9d5b5bc3eb56542ceeba6658d31f54cf401e8468512447834856fb0e61"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c27d98f4e5c4060582f44e58309c1e55134880558f1add7a87c1bc36ecfade19"}, + {file = "yarl-1.20.0-cp310-cp310-win32.whl", hash = "sha256:f4d3fa9b9f013f7050326e165c3279e22850d02ae544ace285674cb6174b5d6d"}, + {file = "yarl-1.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc906b636239631d42eb8a07df8359905da02704a868983265603887ed68c076"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5"}, + {file = "yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6"}, + {file = "yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b"}, + {file = "yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64"}, + {file = "yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384"}, + {file = "yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62"}, + {file = "yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f"}, + {file = "yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac"}, + {file = "yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:119bca25e63a7725b0c9d20ac67ca6d98fa40e5a894bd5d4686010ff73397914"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35d20fb919546995f1d8c9e41f485febd266f60e55383090010f272aca93edcc"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:484e7a08f72683c0f160270566b4395ea5412b4359772b98659921411d32ad26"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d8a3d54a090e0fff5837cd3cc305dd8a07d3435a088ddb1f65e33b322f66a94"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0cf05ae2d3d87a8c9022f3885ac6dea2b751aefd66a4f200e408a61ae9b7f0d"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a884b8974729e3899d9287df46f015ce53f7282d8d3340fa0ed57536b440621c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d8aa8dd89ffb9a831fedbcb27d00ffd9f4842107d52dc9d57e64cb34073d5c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4e88d6c3c8672f45a30867817e4537df1bbc6f882a91581faf1f6d9f0f1b5a"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdb77efde644d6f1ad27be8a5d67c10b7f769804fff7a966ccb1da5a4de4b656"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4ba5e59f14bfe8d261a654278a0f6364feef64a794bd456a8c9e823071e5061c"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d0bf955b96ea44ad914bc792c26a0edcd71b4668b93cbcd60f5b0aeaaed06c64"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27359776bc359ee6eaefe40cb19060238f31228799e43ebd3884e9c589e63b20"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d9c7a1dc0a26efb33e1acb56c8849bd57a693b85f44774356c92d610369efa"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:faa709b66ae0e24c8e5134033187a972d849d87ed0a12a0366bedcc6b5dc14a5"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:44869ee8538208fe5d9342ed62c11cc6a7a1af1b3d0bb79bb795101b6e77f6e0"}, + {file = "yarl-1.20.0-cp39-cp39-win32.whl", hash = "sha256:b7fa0cb9fd27ffb1211cde944b41f5c67ab1c13a13ebafe470b1e206b8459da8"}, + {file = "yarl-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4fad6e5189c847820288286732075f213eabf81be4d08d6cc309912e62be5b7"}, + {file = "yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124"}, + {file = "yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [[package]] name = "zipp" @@ -5340,4 +5409,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "be5328ab34647258a0ba8c9a7966b7abb38c842bd84238d242f05afec60cddbb" +content-hash = "cc15c8ee6b064b3fda85177c0f1c24a57880c401682fe62daefc2d0f4043150a" diff --git a/prowler/lib/powershell/powershell.py b/prowler/lib/powershell/powershell.py index 1e13a74306..f6e058afcd 100644 --- a/prowler/lib/powershell/powershell.py +++ b/prowler/lib/powershell/powershell.py @@ -191,9 +191,10 @@ class PowerShellSession: error_thread.daemon = True error_thread.start() + error_result = None try: result = result_queue.get(timeout=timeout) or default - error_result = error_queue.get(timeout=1) or None + error_result = error_queue.get(timeout=1) except queue.Empty: result = default diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py index 81b359728c..a8e4ce4ec2 100644 --- a/prowler/providers/m365/m365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -616,12 +616,12 @@ class M365Provider(Provider): browser_auth: bool = False, tenant_id: str = None, region: str = "M365Global", - raise_on_exception=True, - client_id=None, - client_secret=None, - user=None, - encrypted_password=None, - provider_id=None, + raise_on_exception: bool = True, + client_id: str = None, + client_secret: str = None, + user: str = None, + encrypted_password: str = None, + provider_id: str = None, ) -> Connection: """Test connection to M365 tenant and PowerShell modules. diff --git a/pyproject.toml b/pyproject.toml index b0f76fa808..ce1f648702 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ coverage = "7.6.12" docker = "7.1.0" flake8 = "7.1.2" freezegun = "1.5.1" +marshmallow = ">=3.15.0,<4.0.0" mock = "5.2.0" moto = {extras = ["all"], version = "5.0.28"} openapi-schema-validator = "0.6.3" From 25b1efe532aa1b3774dba62f1404399640897aaf Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 08:46:14 +0200 Subject: [PATCH 238/359] feat(exchange): add new check `exchange_organization_mailtips_enabled` (#7637) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- docs/tutorials/configuration_file.md | 5 + prowler/CHANGELOG.md | 1 + prowler/config/config.py | 2 +- prowler/config/config.yaml | 3 + .../__init__.py | 0 ...rganization_mailtips_enabled.metadata.json | 30 ++++ .../exchange_organization_mailtips_enabled.py | 54 +++++++ .../services/exchange/exchange_service.py | 16 +++ tests/config/fixtures/config.yaml | 13 ++ ...anization_mailbox_auditing_enabled_test.py | 16 ++- ...ange_organization_mailtips_enabled_test.py | 136 ++++++++++++++++++ .../exchange/exchange_service_test.py | 14 +- 12 files changed, 286 insertions(+), 4 deletions(-) create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py diff --git a/docs/tutorials/configuration_file.md b/docs/tutorials/configuration_file.md index 9ee25ea7e7..78b9865183 100644 --- a/docs/tutorials/configuration_file.md +++ b/docs/tutorials/configuration_file.md @@ -106,6 +106,7 @@ The following list includes all the Microsoft 365 checks with configurable varia |---------------------------------------------------------------|--------------------------------------------------|-----------------| | `entra_admin_users_sign_in_frequency_enabled` | `sign_in_frequency` | Integer | | `teams_external_file_sharing_restricted` | `allowed_cloud_storage_services` | List of Strings | +| `exchange_organization_mailtips_enabled` | `recommended_mailtips_large_audience_threshold` | Integer | ## Config YAML File Structure @@ -520,5 +521,9 @@ m365: #"allow_google_drive", #"allow_share_file", ] + # Exchange Organization Settings + # m365.exchange_organization_mailtips_enabled + recommended_mailtips_large_audience_threshold: 25 # maximum number of recipients + ``` diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 34601abebf..5ad2d47b7b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) +- Add new check for MailTips full enabled for Exchange in M365 [(#7637)](https://github.com/prowler-cloud/prowler/pull/7637) ### Fixed diff --git a/prowler/config/config.py b/prowler/config/config.py index 38d0134859..52bd2fd742 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -132,7 +132,7 @@ def load_and_validate_config_file(provider: str, config_file_path: str) -> dict: else: config = config_file if config_file else {} # Not to break Azure, K8s and GCP does not support or use the old config format - if provider in ["azure", "gcp", "kubernetes"]: + if provider in ["azure", "gcp", "kubernetes", "m365"]: config = {} return config diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index 26b196e178..0ee0ceee19 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -497,3 +497,6 @@ m365: #"allow_google_drive", #"allow_share_file", ] + # Exchange Organization Settings + # m365.exchange_organization_mailtips_enabled + recommended_mailtips_large_audience_threshold: 25 # maximum number of recipients diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.metadata.json new file mode 100644 index 0000000000..bb727e4c3f --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_organization_mailtips_enabled", + "CheckTitle": "Ensure MailTips are enabled for end users.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Exchange Organization Configuration", + "Description": "Ensure that MailTips are enabled in Exchange Online to provide users with informative messages while composing emails, helping to avoid issues such as sending to large groups or external recipients unintentionally.", + "Risk": "Without MailTips, users may inadvertently send sensitive information externally or generate non-delivery reports, leading to communication errors and potential data exposure.", + "RelatedUrl": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/mailtips/mailtips", + "Remediation": { + "Code": { + "CLI": "$TipsParams = @{ MailTipsAllTipsEnabled = $true; MailTipsExternalRecipientsTipsEnabled = $true; MailTipsGroupMetricsEnabled = $true; MailTipsLargeAudienceThreshold = '25' }; Set-OrganizationConfig @TipsParams", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable MailTips features in Exchange Online and configure the large audience threshold appropriately to assist users when composing emails.", + "Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-organizationconfig?view=exchange-ps" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.py b/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.py new file mode 100644 index 0000000000..52aa8dc060 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled.py @@ -0,0 +1,54 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_organization_mailtips_enabled(Check): + """ + Check if MailTips are enabled for Exchange Online. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check for MailTips in Exchange Online. + + This method checks if MailTips are enabled in the Exchange organization configuration. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + organization_config = exchange_client.organization_config + if organization_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=organization_config, + resource_name=organization_config.name, + resource_id=organization_config.guid, + ) + report.status = "FAIL" + report.status_extended = ( + "MailTips are not fully enabled for Exchange Online." + ) + + if ( + organization_config.mailtips_enabled + and organization_config.mailtips_external_recipient_enabled + and organization_config.mailtips_group_metrics_enabled + and organization_config.mailtips_large_audience_threshold + <= exchange_client.audit_config.get( + "recommended_mailtips_large_audience_threshold", 25 + ) + ): + report.status = "PASS" + report.status_extended = ( + "MailTips are fully enabled for Exchange Online." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index dbcc44499f..eb76c7bf9e 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -37,6 +37,18 @@ class Exchange(M365Service): audit_disabled=organization_configuration.get( "AuditDisabled", False ), + mailtips_enabled=organization_configuration.get( + "MailTipsAllTipsEnabled", True + ), + mailtips_external_recipient_enabled=organization_configuration.get( + "MailTipsExternalRecipientsTipsEnabled", False + ), + mailtips_group_metrics_enabled=organization_configuration.get( + "MailTipsGroupMetricsEnabled", True + ), + mailtips_large_audience_threshold=organization_configuration.get( + "MailTipsLargeAudienceThreshold", 25 + ), ) except Exception as error: logger.error( @@ -137,6 +149,10 @@ class Organization(BaseModel): name: str guid: str audit_disabled: bool + mailtips_enabled: bool + mailtips_external_recipient_enabled: bool + mailtips_group_metrics_enabled: bool + mailtips_large_audience_threshold: int class MailboxAuditConfig(BaseModel): diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml index 4d528e97da..b15b6de402 100644 --- a/tests/config/fixtures/config.yaml +++ b/tests/config/fixtures/config.yaml @@ -435,3 +435,16 @@ m365: # Conditional Access Policy # policy.session_controls.sign_in_frequency.frequency in hours sign_in_frequency: 4 + # Teams Settings + # m365.teams_external_file_sharing_restricted + allowed_cloud_storage_services: + [ + #"allow_box", + #"allow_drop_box", + #"allow_egnyte", + #"allow_google_drive", + #"allow_share_file", + ] + # Exchange Organization Settings + # m365.exchange_organization_mailtips_enabled + recommended_mailtips_large_audience_threshold: 25 # maximum number of recipients diff --git a/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py index 104b050541..82860f3b7d 100644 --- a/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py +++ b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py @@ -57,7 +57,13 @@ class Test_exchange_organization_mailbox_auditing_enabled: ) exchange_client.organization_config = Organization( - audit_disabled=True, name="test", guid="test" + audit_disabled=True, + name="test", + guid="test", + mailtips_enabled=True, + mailtips_external_recipient_enabled=True, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, ) check = exchange_organization_mailbox_auditing_enabled() @@ -99,7 +105,13 @@ class Test_exchange_organization_mailbox_auditing_enabled: ) exchange_client.organization_config = Organization( - audit_disabled=False, name="test", guid="test" + audit_disabled=False, + name="test", + guid="test", + mailtips_enabled=True, + mailtips_external_recipient_enabled=True, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, ) check = exchange_organization_mailbox_auditing_enabled() diff --git a/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py new file mode 100644 index 0000000000..cbcc6266c5 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py @@ -0,0 +1,136 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_organization_mailtips_enabled: + def test_no_organization(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.organization_config = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled import ( + exchange_organization_mailtips_enabled, + ) + + check = exchange_organization_mailtips_enabled() + result = check.execute() + assert result == [] + + def test_mailtips_not_fully_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled import ( + exchange_organization_mailtips_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.audit_config = { + "recommended_mailtips_large_audience_threshold": 25 + } + + exchange_client.organization_config = Organization( + name="test-org", + guid="org-guid", + audit_disabled=False, + mailtips_enabled=False, + mailtips_external_recipient_enabled=False, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, + ) + + check = exchange_organization_mailtips_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "MailTips are not fully enabled for Exchange Online." + ) + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" + assert result[0].resource == exchange_client.organization_config.dict() + + def test_mailtips_fully_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_mailtips_enabled.exchange_organization_mailtips_enabled import ( + exchange_organization_mailtips_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.audit_config = { + "recommended_mailtips_large_audience_threshold": 25 + } + + exchange_client.organization_config = Organization( + name="test-org", + guid="org-guid", + audit_disabled=False, + mailtips_enabled=True, + mailtips_external_recipient_enabled=True, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, + ) + + check = exchange_organization_mailtips_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "MailTips are fully enabled for Exchange Online." + ) + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" + assert result[0].resource == exchange_client.organization_config.dict() diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 42cc16a507..0a30e0c7f7 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -14,7 +14,15 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider def mock_exchange_get_organization_config(_): - return Organization(audit_disabled=True, name="test", guid="test") + return Organization( + audit_disabled=True, + name="test", + guid="test", + mailtips_enabled=True, + mailtips_external_recipient_enabled=False, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, + ) def mock_exchange_get_mailbox_audit_config(_): @@ -94,6 +102,10 @@ class Test_Exchange_Service: assert organization_config.name == "test" assert organization_config.guid == "test" assert organization_config.audit_disabled is True + assert organization_config.mailtips_enabled is True + assert organization_config.mailtips_external_recipient_enabled is False + assert organization_config.mailtips_group_metrics_enabled is True + assert organization_config.mailtips_large_audience_threshold == 25 exchange_client.powershell.close() From e7d249784ded43a104878605c60dd5aae5d24e04 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 09:05:53 +0200 Subject: [PATCH 239/359] feat(exchange): add new check `exchange_transport_config_smtp_auth_disabled` (#7640) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 17 +++ .../services/exchange/exchange_service.py | 23 ++++ .../__init__.py | 0 ...rt_config_smtp_auth_disabled.metadata.json | 30 +++++ ...nge_transport_config_smtp_auth_disabled.py | 44 +++++++ .../exchange/exchange_service_test.py | 27 +++++ ...ransport_config_smtp_auth_disabled_test.py | 112 ++++++++++++++++++ 8 files changed, 254 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 5ad2d47b7b..22cce0e59d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) +- Add new check for SMTP Auth disabled for Exchange in M365 [(#7640)](https://github.com/prowler-cloud/prowler/pull/7640) - Add new check for MailTips full enabled for Exchange in M365 [(#7637)](https://github.com/prowler-cloud/prowler/pull/7637) ### Fixed diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index df4a26dfd8..1046a45b7d 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -487,6 +487,23 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + def get_transport_config(self) -> dict: + """ + Get Exchange Online Transport Configuration. + + Retrieves the current transport configuration settings for Exchange Online. + + Returns: + dict: Transport configuration settings in JSON format. + + Example: + >>> get_transport_config() + { + "SmtpClientAuthenticationDisabled": True, + } + """ + return self.execute("Get-TransportConfig | ConvertTo-Json", json_parse=True) + # This function is used to install the required M365 PowerShell modules in Docker containers def initialize_m365_powershell_modules(): diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index eb76c7bf9e..03ad304c5e 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -14,6 +14,7 @@ class Exchange(M365Service): self.mailboxes_config = [] self.external_mail_config = [] self.transport_rules = [] + self.transport_config = None self.mailbox_policy = None if self.powershell: @@ -22,6 +23,7 @@ class Exchange(M365Service): self.mailboxes_config = self._get_mailbox_audit_config() self.external_mail_config = self._get_external_mail_config() self.transport_rules = self._get_transport_rules() + self.transport_config = self._get_transport_config() self.mailbox_policy = self._get_mailbox_policy() self.powershell.close() @@ -126,6 +128,23 @@ class Exchange(M365Service): ) return transport_rules + def _get_transport_config(self): + logger.info("Microsoft365 - Getting transport configuration...") + transport_config = [] + try: + transport_configuration = self.powershell.get_transport_config() + if transport_configuration: + transport_config = TransportConfig( + smtp_auth_disabled=transport_configuration.get( + "SmtpClientAuthenticationDisabled", False + ), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return transport_config + def _get_mailbox_policy(self): logger.info("Microsoft365 - Getting mailbox policy configuration...") mailboxes_policy = None @@ -172,6 +191,10 @@ class TransportRule(BaseModel): sender_domain_is: list[str] +class TransportConfig(BaseModel): + smtp_auth_disabled: bool + + class MailboxPolicy(BaseModel): id: str additional_storage_enabled: bool diff --git a/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.metadata.json new file mode 100644 index 0000000000..023efb30b3 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_transport_config_smtp_auth_disabled", + "CheckTitle": "Ensure SMTP AUTH is disabled.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Transport Config", + "Description": "Ensure that SMTP AUTH is disabled at the organization level in Exchange Online to reduce exposure to legacy protocols that can be exploited for malicious use.", + "Risk": "Leaving SMTP AUTH enabled allows legacy clients to authenticate using outdated methods, increasing the risk of credential compromise and unauthorized email sending.", + "RelatedUrl": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission", + "Remediation": { + "Code": { + "CLI": "Set-TransportConfig -SmtpClientAuthenticationDisabled $true", + "NativeIaC": "", + "Other": "1. Navigate to Exchange admin center https://admin.exchange.microsoft.com. 2. Select Settings > Mail flow. 3. Ensure 'Turn off SMTP AUTH protocol for your organization' is checked.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable SMTP AUTH at the organization level to support secure, modern authentication practices and block legacy protocol usage.", + "Url": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.py b/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.py new file mode 100644 index 0000000000..f842c59b87 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled.py @@ -0,0 +1,44 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_transport_config_smtp_auth_disabled(Check): + """Check if SMTP AUTH is disabled in Exchange Online Transport Config. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for SMTP AUTH setting in Transport Config. + + This method checks if SMTP AUTH is disabled at the organization level in Exchange Online. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + transport_config = exchange_client.transport_config + if transport_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=transport_config, + resource_name="Transport Configuration", + resource_id="transport_config", + ) + report.status = "FAIL" + report.status_extended = ( + "SMTP AUTH is enabled in the Exchange Online Transport Config." + ) + + if transport_config.smtp_auth_disabled: + report.status = "PASS" + report.status_extended = ( + "SMTP AUTH is disabled in the Exchange Online Transport Config." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 0a30e0c7f7..60e6e853eb 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -8,6 +8,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( MailboxAuditConfig, MailboxPolicy, Organization, + TransportConfig, TransportRule, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -60,6 +61,12 @@ def mock_exchange_get_transport_rules(_): ] +def mock_exchange_get_transport_config(_): + return TransportConfig( + smtp_auth_disabled=True, + ) + + def mock_exchange_get_mailbox_policy(_): return MailboxPolicy( id="test", @@ -203,3 +210,23 @@ class Test_Exchange_Service: assert mailbox_policy.id == "test" assert mailbox_policy.additional_storage_enabled is True exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_transport_config", + new=mock_exchange_get_transport_config, + ) + def test_get_transport_config(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + transport_config = exchange_client.transport_config + assert transport_config.smtp_auth_disabled is True + + exchange_client.powershell.close() diff --git a/tests/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled_test.py b/tests/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled_test.py new file mode 100644 index 0000000000..b1e904b473 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_transport_config_smtp_auth_disabled/exchange_transport_config_smtp_auth_disabled_test.py @@ -0,0 +1,112 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_transport_config_smtp_auth_disabled: + def test_no_transport_config(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.transport_config = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled import ( + exchange_transport_config_smtp_auth_disabled, + ) + + check = exchange_transport_config_smtp_auth_disabled() + result = check.execute() + assert len(result) == 0 + + def test_smtp_auth_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_service import ( + TransportConfig, + ) + from prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled import ( + exchange_transport_config_smtp_auth_disabled, + ) + + exchange_client.transport_config = TransportConfig(smtp_auth_disabled=False) + + check = exchange_transport_config_smtp_auth_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "SMTP AUTH is enabled in the Exchange Online Transport Config." + ) + assert result[0].resource == exchange_client.transport_config.dict() + assert result[0].resource_name == "Transport Configuration" + assert result[0].resource_id == "transport_config" + assert result[0].location == "global" + + def test_smtp_auth_disabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_service import ( + TransportConfig, + ) + from prowler.providers.m365.services.exchange.exchange_transport_config_smtp_auth_disabled.exchange_transport_config_smtp_auth_disabled import ( + exchange_transport_config_smtp_auth_disabled, + ) + + exchange_client.transport_config = TransportConfig(smtp_auth_disabled=True) + + check = exchange_transport_config_smtp_auth_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "SMTP AUTH is disabled in the Exchange Online Transport Config." + ) + assert result[0].resource == exchange_client.transport_config.dict() + assert result[0].resource_name == "Transport Configuration" + assert result[0].resource_id == "transport_config" + assert result[0].location == "global" From 3949806b5d9de1be9a0b9c7a575e285f784651c4 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 10:48:30 +0200 Subject: [PATCH 240/359] feat(exchange): add new check `exchange_mailbox_properties_auditing_e3_enabled` (#7642) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 66 +++++ .../__init__.py | 0 ...operties_auditing_e3_enabled.metadata.json | 30 +++ ..._mailbox_properties_auditing_e3_enabled.py | 74 ++++++ .../services/exchange/exchange_service.py | 97 +++++++ ...box_properties_auditing_e3_enabled_test.py | 240 ++++++++++++++++++ .../exchange/exchange_service_test.py | 115 +++++++++ 8 files changed, 623 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 22cce0e59d..50649a547c 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) +- Add new check for Auditing Mailbox on E3 users is enabled for Exchange in M365 [(#7642)](https://github.com/prowler-cloud/prowler/pull/7642) - Add new check for SMTP Auth disabled for Exchange in M365 [(#7640)](https://github.com/prowler-cloud/prowler/pull/7640) - Add new check for MailTips full enabled for Exchange in M365 [(#7637)](https://github.com/prowler-cloud/prowler/pull/7637) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 1046a45b7d..9dc5d6ff1a 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -487,6 +487,72 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + def get_mailbox_audit_properties(self) -> dict: + """ + Get Mailbox Properties. + + Retrieves the properties of all mailboxes in the organization in Exchange Online. + + Args: + mailbox (str): The email address or identifier of the mailbox. + + Returns: + dict: Mailbox properties in JSON format. + + Example: + >>> get_mailbox_properties() + { + "UserPrincipalName": "User1", + "AuditEnabled": "false" + "AuditAdmin": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send" + ], + "AuditDelegate": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed" + ], + "AuditOwner": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send" + ], + "AuditLogAgeLimit": "90", + "Identity": "User1", + } + """ + return self.execute( + "Get-EXOMailbox -PropertySets Audit -ResultSize Unlimited | ConvertTo-Json", + json_parse=True, + ) + def get_transport_config(self) -> dict: """ Get Exchange Online Transport Configuration. diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json new file mode 100644 index 0000000000..fccbe84533 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_mailbox_properties_auditing_e3_enabled", + "CheckTitle": "Ensure mailbox auditing for E3 users is enabled.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Mailboxes Properties", + "Description": "Ensure mailbox auditing is enabled for all E3-licensed user mailboxes, including the configuration of audit actions for owners, delegates, and admins beyond the Microsoft defaults.", + "Risk": "If auditing is not properly enabled and configured, critical mailbox actions may go unrecorded, reducing the ability to investigate incidents, enforce compliance, or detect malicious behavior.", + "RelatedUrl": "https://learn.microsoft.com/en-us/purview/audit-mailboxes?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "$AuditAdmin = @(\"ApplyRecord\", \"Copy\", \"Create\", \"FolderBind\", \"HardDelete\", \"Move\", \"MoveToDeletedItems\", \"SendAs\", \"SendOnBehalf\", \"SoftDelete\", \"Update\", \"UpdateCalendarDelegation\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $AuditDelegate = @(\"ApplyRecord\", \"Create\", \"FolderBind\", \"HardDelete\", \"Move\", \"MoveToDeletedItems\", \"SendAs\", \"SendOnBehalf\", \"SoftDelete\", \"Update\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $AuditOwner = @(\"ApplyRecord\", \"Create\", \"HardDelete\", \"MailboxLogin\", \"Move\", \"MoveToDeletedItems\", \"SoftDelete\", \"Update\", \"UpdateCalendarDelegation\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $MBX = Get-EXOMailbox -ResultSize Unlimited | Where-Object { $_.RecipientTypeDetails -eq \"UserMailbox\" }; $MBX | Set-Mailbox -AuditEnabled $true -AuditLogAgeLimit 90 -AuditAdmin $AuditAdmin -AuditDelegate $AuditDelegate -AuditOwner $AuditOwner", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable mailbox auditing for all E3 user mailboxes and configure auditing for key mailbox actions for owners, delegates, and admins.", + "Url": "https://learn.microsoft.com/en-us/purview/audit-mailboxes?view=o365-worldwide" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py new file mode 100644 index 0000000000..583d7a09b3 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py @@ -0,0 +1,74 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client +from prowler.providers.m365.services.exchange.exchange_service import ( + AuditAdmin, + AuditDelegate, + AuditOwner, +) + + +class exchange_mailbox_properties_auditing_e3_enabled(Check): + """ + Check to ensure that mailbox auditing properties are enabled and properly configured. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to validate that mailbox auditing properties are enabled and properly configured. + + This method retrieves all mailbox audit properties from the Exchange service and evaluates + whether auditing is enabled and correctly configured for each mailbox. A report is generated + for each mailbox. + + Returns: + List[CheckReportM365]: A list of findings with the status of each mailbox. + """ + findings = [] + + required_admin = {e.value for e in AuditAdmin} + required_delegate = {e.value for e in AuditDelegate} + required_owner = {e.value for e in AuditOwner} + + for mailbox in exchange_client.mailbox_audit_properties: + report = CheckReportM365( + metadata=self.metadata(), + resource=mailbox, + resource_name=mailbox.name, + resource_id=mailbox.identity, + ) + + report.status = "FAIL" + report.status_extended = ( + f"Mailbox Audit Properties for Mailbox {mailbox.name} is not enabled." + ) + + if mailbox.audit_enabled: + audit_admin = set(mailbox.audit_admin or []) + audit_delegate = set(mailbox.audit_delegate or []) + audit_owner = set(mailbox.audit_owner or []) + + if ( + required_admin.issubset(audit_admin) + and required_delegate.issubset(audit_delegate) + and required_owner.issubset(audit_owner) + ): + # The limit for E3 is 90 days, but we check >= 90 because E5 users can set it to more than 90 days + if mailbox.audit_log_age >= 90: + report.status = "PASS" + report.status_extended = f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled and properly configured." + else: + report.status_extended = f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled and properly configured but the audit log age is less than 90 days." + else: + report.status_extended = ( + f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled but not properly configured. " + f"Missing audit actions may exist." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 03ad304c5e..8417e9c40e 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -1,3 +1,4 @@ +from enum import Enum from typing import Optional from pydantic import BaseModel @@ -16,6 +17,7 @@ class Exchange(M365Service): self.transport_rules = [] self.transport_config = None self.mailbox_policy = None + self.mailbox_audit_properties = [] if self.powershell: self.powershell.connect_exchange_online() @@ -25,6 +27,7 @@ class Exchange(M365Service): self.transport_rules = self._get_transport_rules() self.transport_config = self._get_transport_config() self.mailbox_policy = self._get_mailbox_policy() + self.mailbox_audit_properties = self._get_mailbox_audit_properties() self.powershell.close() def _get_organization_config(self): @@ -163,6 +166,44 @@ class Exchange(M365Service): ) return mailboxes_policy + def _get_mailbox_audit_properties(self): + logger.info("Microsoft365 - Getting mailbox audit properties...") + mailbox_audit_properties = [] + try: + mailbox_audit_properties_info = ( + self.powershell.get_mailbox_audit_properties() + ) + if not mailbox_audit_properties_info: + return mailbox_audit_properties + if isinstance(mailbox_audit_properties_info, dict): + mailbox_audit_properties_info = [mailbox_audit_properties_info] + for mailbox_audit_property in mailbox_audit_properties_info: + if mailbox_audit_property: + mailbox_audit_properties.append( + MailboxAuditProperties( + name=mailbox_audit_property.get("UserPrincipalName", ""), + audit_enabled=mailbox_audit_property.get( + "AuditEnabled", False + ), + audit_admin=mailbox_audit_property.get("AuditAdmin", []), + audit_delegate=mailbox_audit_property.get( + "AuditDelegate", [] + ), + audit_owner=mailbox_audit_property.get("AuditOwner", []), + audit_log_age=int( + mailbox_audit_property.get( + "AuditLogAgeLimit", "90.00:00:00" + ).split(".")[0] + ), + identity=mailbox_audit_property.get("Identity", ""), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return mailbox_audit_properties + class Organization(BaseModel): name: str @@ -198,3 +239,59 @@ class TransportConfig(BaseModel): class MailboxPolicy(BaseModel): id: str additional_storage_enabled: bool + + +class MailboxAuditProperties(BaseModel): + name: str + audit_enabled: bool + audit_admin: list[str] + audit_delegate: list[str] + audit_owner: list[str] + audit_log_age: int + identity: str + + +class AuditAdmin(Enum): + APPLY_RECORD = "ApplyRecord" + COPY = "Copy" + CREATE = "Create" + FOLDER_BIND = "FolderBind" + HARD_DELETE = "HardDelete" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SEND_AS = "SendAs" + SEND_ON_BEHALF = "SendOnBehalf" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_CALENDAR_DELEGATION = "UpdateCalendarDelegation" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" + + +class AuditDelegate(Enum): + APPLY_RECORD = "ApplyRecord" + CREATE = "Create" + FOLDER_BIND = "FolderBind" + HARD_DELETE = "HardDelete" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SEND_AS = "SendAs" + SEND_ON_BEHALF = "SendOnBehalf" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" + + +class AuditOwner(Enum): + APPLY_RECORD = "ApplyRecord" + CREATE = "Create" + HARD_DELETE = "HardDelete" + MAILBOX_LOGIN = "MailboxLogin" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_CALENDAR_DELEGATION = "UpdateCalendarDelegation" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" diff --git a/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py b/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py new file mode 100644 index 0000000000..9985341194 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py @@ -0,0 +1,240 @@ +from unittest import mock + +from prowler.providers.m365.services.exchange.exchange_service import ( + AuditAdmin, + AuditDelegate, + AuditOwner, + MailboxAuditProperties, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_mailbox_properties_auditing_e3_enabled: + def test_no_auditing_mailboxes(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 0 + + def test_auditing_fully_configured_and_log_age_valid(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User1", + audit_enabled=True, + audit_admin=[e.value for e in AuditAdmin], + audit_delegate=[e.value for e in AuditDelegate], + audit_owner=[e.value for e in AuditOwner], + audit_log_age=180, + identity="User1", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User1 is enabled and properly configured." + ) + assert result[0].resource_name == "User1" + assert result[0].resource_id == "User1" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_enabled_but_incomplete_configuration(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User2", + audit_enabled=True, + audit_admin=["SendAs"], + audit_delegate=["Send"], + audit_owner=["Update"], + audit_log_age=180, + identity="User2", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User2 is enabled but not properly configured. Missing audit actions may exist." + ) + assert result[0].resource_name == "User2" + assert result[0].resource_id == "User2" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_not_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User3", + audit_enabled=False, + audit_admin=[], + audit_delegate=[], + audit_owner=[], + audit_log_age=0, + identity="User3", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User3 is not enabled." + ) + assert result[0].resource_name == "User3" + assert result[0].resource_id == "User3" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_enabled_but_log_age_too_low(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User4", + audit_enabled=True, + audit_admin=[e.value for e in AuditAdmin], + audit_delegate=[e.value for e in AuditDelegate], + audit_owner=[e.value for e in AuditOwner], + audit_log_age=30, + identity="User4", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User4 is enabled and properly configured but the audit log age is less than 90 days." + ) + assert result[0].resource_name == "User4" + assert result[0].resource_id == "User4" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 60e6e853eb..73cf90c6d9 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, ExternalMailConfig, MailboxAuditConfig, + MailboxAuditProperties, MailboxPolicy, Organization, TransportConfig, @@ -74,6 +75,57 @@ def mock_exchange_get_mailbox_policy(_): ) +def mock_exchange_get_mailbox_audit_properties(_): + return [ + MailboxAuditProperties( + name="User1", + audit_enabled=False, + audit_admin=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ], + audit_delegate=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed", + ], + audit_owner=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ], + audit_log_age=90, + identity="test", + ) + ] + + class Test_Exchange_Service: def test_get_client(self): with ( @@ -230,3 +282,66 @@ class Test_Exchange_Service: assert transport_config.smtp_auth_disabled is True exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_mailbox_audit_properties", + new=mock_exchange_get_mailbox_audit_properties, + ) + def test_get_mailbox_audit_properties(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + mailbox_audit_properties = exchange_client.mailbox_audit_properties + assert len(mailbox_audit_properties) == 1 + assert mailbox_audit_properties[0].name == "User1" + assert mailbox_audit_properties[0].audit_enabled is False + assert mailbox_audit_properties[0].audit_admin == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ] + assert mailbox_audit_properties[0].audit_delegate == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed", + ] + assert mailbox_audit_properties[0].audit_owner == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ] + assert mailbox_audit_properties[0].audit_log_age == 90 + assert mailbox_audit_properties[0].identity == "test" + exchange_client.powershell.close() From cccd69f27cbae5c3bb5f584ae69882241d420361 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 11:58:56 +0200 Subject: [PATCH 241/359] feat(exchange): add new check `exchange_roles_assignment_policy_addins_disabled` (#7644) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 21 +++ .../__init__.py | 0 ...nment_policy_addins_disabled.metadata.json | 30 ++++ ...roles_assignment_policy_addins_disabled.py | 50 +++++++ .../services/exchange/exchange_service.py | 38 ++++++ ..._assignment_policy_addins_disabled_test.py | 129 ++++++++++++++++++ .../exchange/exchange_service_test.py | 54 ++++++++ 8 files changed, 323 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 50649a547c..19426c4e10 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) +- Add new check for Roles Assignment Policy with no AddIns for Exchange in M365 [(#7644)](https://github.com/prowler-cloud/prowler/pull/7644) - Add new check for Auditing Mailbox on E3 users is enabled for Exchange in M365 [(#7642)](https://github.com/prowler-cloud/prowler/pull/7642) - Add new check for SMTP Auth disabled for Exchange in M365 [(#7640)](https://github.com/prowler-cloud/prowler/pull/7640) - Add new check for MailTips full enabled for Exchange in M365 [(#7637)](https://github.com/prowler-cloud/prowler/pull/7637) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 9dc5d6ff1a..9bf39060c3 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -487,6 +487,27 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + def get_role_assignment_policies(self) -> dict: + """ + Get Role Assignment Policies. + + Retrieves the current role assignment policies for Exchange Online. + + Returns: + dict: Role assignment policies in JSON format. + + Example: + >>> get_role_assignment_policies() + { + "Name": "Default Role Assignment Policy", + "Guid": "12345678-1234-1234-1234-123456789012", + "AssignedRoles": ["MyRole"] + } + """ + return self.execute( + "Get-RoleAssignmentPolicy | ConvertTo-Json", json_parse=True + ) + def get_mailbox_audit_properties(self) -> dict: """ Get Mailbox Properties. diff --git a/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.metadata.json new file mode 100644 index 0000000000..7764d43679 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_roles_assignment_policy_addins_disabled", + "CheckTitle": "Ensure there is no policy with Outlook add-ins allowed.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Role Assignment Policy", + "Description": "Restricting users from installing Outlook add-ins reduces the risk of data exposure or exploitation through unapproved or vulnerable add-ins.", + "Risk": "Allowing users to install add-ins may expose sensitive information or introduce malicious behavior through third-party integrations. Disabling this capability mitigates the risk of unauthorized data access.", + "RelatedUrl": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/add-ins-for-outlook/specify-who-can-install-and-manage-add-ins", + "Remediation": { + "Code": { + "CLI": "$policy = \"Role Assignment Policy - Prevent Add-ins\"; $roles = \"MyTextMessaging\", \"MyDistributionGroups\", \"MyMailSubscriptions\", \"MyBaseOptions\", \"MyVoiceMail\", \"MyProfileInformation\", \"MyContactInformation\", \"MyRetentionPolicies\", \"MyDistributionGroupMembership\"; New-RoleAssignmentPolicy -Name $policy -Roles $roles; Set-RoleAssignmentPolicy -id $policy -IsDefault; Get-EXOMailbox -ResultSize Unlimited | Set-Mailbox -RoleAssignmentPolicy $policy", + "NativeIaC": "", + "Other": "1. Navigate to Exchange admin center https://admin.exchange.microsoft.com. 2. Click to expand Roles > User roles. 3. Select Default Role Assignment Policy. 4. In the right pane, click Manage permissions. 5. Uncheck My Custom Apps, My Marketplace Apps and My ReadWriteMailboxApps under Other roles. 6. Save changes.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict Outlook add-in installation by updating the Role Assignment Policy to exclude roles that allow app installation.", + "Url": "https://learn.microsoft.com/en-us/exchange/permissions-exo/role-assignment-policies" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.py b/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.py new file mode 100644 index 0000000000..74f770352b --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled.py @@ -0,0 +1,50 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client +from prowler.providers.m365.services.exchange.exchange_service import AddinRoles + + +class exchange_roles_assignment_policy_addins_disabled(Check): + """Check if any Exchange role assignment policy allows Outlook add-ins. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """Execute the check for role assignment policies that allow Outlook add-ins. + + This method checks all Exchange Online Role Assignment Policies to verify + whether any of them allow the installation of add-ins by including risky roles. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + + addin_roles = [e.value for e in AddinRoles] + + for policy in exchange_client.role_assignment_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.name, + resource_id=policy.id, + ) + + report.status = "PASS" + report.status_extended = f"Role assignment policy '{policy.name}' does not allow Outlook add-ins." + + risky_roles_found = [] + for role in policy.assigned_roles: + if role in addin_roles: + risky_roles_found.append(role) + + if risky_roles_found: + report.status = "FAIL" + report.status_extended = f"Role assignment policy '{policy.name}' allows Outlook add-ins via roles: {', '.join(risky_roles_found)}." + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 8417e9c40e..af2ecbce03 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -17,6 +17,7 @@ class Exchange(M365Service): self.transport_rules = [] self.transport_config = None self.mailbox_policy = None + self.role_assignment_policies = [] self.mailbox_audit_properties = [] if self.powershell: @@ -27,6 +28,7 @@ class Exchange(M365Service): self.transport_rules = self._get_transport_rules() self.transport_config = self._get_transport_config() self.mailbox_policy = self._get_mailbox_policy() + self.role_assignment_policies = self._get_role_assignment_policies() self.mailbox_audit_properties = self._get_mailbox_audit_properties() self.powershell.close() @@ -166,6 +168,30 @@ class Exchange(M365Service): ) return mailboxes_policy + def _get_role_assignment_policies(self): + logger.info("Microsoft365 - Getting role assignment policies...") + role_assignment_policies = [] + try: + policies_data = self.powershell.get_role_assignment_policies() + if not policies_data: + return role_assignment_policies + if isinstance(policies_data, dict): + policies_data = [policies_data] + for policy in policies_data: + if policy: + role_assignment_policies.append( + RoleAssignmentPolicy( + name=policy.get("Name", ""), + id=policy.get("Guid", ""), + assigned_roles=policy.get("AssignedRoles", []), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return role_assignment_policies + def _get_mailbox_audit_properties(self): logger.info("Microsoft365 - Getting mailbox audit properties...") mailbox_audit_properties = [] @@ -241,6 +267,18 @@ class MailboxPolicy(BaseModel): additional_storage_enabled: bool +class RoleAssignmentPolicy(BaseModel): + name: str + id: str + assigned_roles: list[str] + + +class AddinRoles(Enum): + MY_CUSTOM_APPS = "My Custom Apps" + MY_MARKETPLACE_APPS = "My Marketplace Apps" + MY_READWRITE_MAILBOX_APPS = "My ReadWriteMailbox Apps" + + class MailboxAuditProperties(BaseModel): name: str audit_enabled: bool diff --git a/tests/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled_test.py b/tests/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled_test.py new file mode 100644 index 0000000000..1f28ee407f --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_roles_assignment_policy_addins_disabled/exchange_roles_assignment_policy_addins_disabled_test.py @@ -0,0 +1,129 @@ +from unittest import mock + +from prowler.providers.m365.services.exchange.exchange_service import ( + RoleAssignmentPolicy, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_roles_assignment_policy_addins_disabled: + def test_no_policies(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online", + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled import ( + exchange_roles_assignment_policy_addins_disabled, + ) + + exchange_client.role_assignment_policies = [] + + check = exchange_roles_assignment_policy_addins_disabled() + result = check.execute() + + assert len(result) == 0 + + def test_policy_with_no_addin_roles(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online", + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled import ( + exchange_roles_assignment_policy_addins_disabled, + ) + + exchange_client.role_assignment_policies = [ + RoleAssignmentPolicy( + name="Policy1", + id="id-policy1", + assigned_roles=["My Base Options", "My Voice Mail"], + ) + ] + + check = exchange_roles_assignment_policy_addins_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Role assignment policy 'Policy1' does not allow Outlook add-ins." + ) + assert result[0].resource_name == "Policy1" + assert result[0].resource_id == "id-policy1" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.role_assignment_policies[0].dict() + ) + + def test_policy_with_addin_roles(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online", + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_roles_assignment_policy_addins_disabled.exchange_roles_assignment_policy_addins_disabled import ( + exchange_roles_assignment_policy_addins_disabled, + ) + + exchange_client.role_assignment_policies = [ + RoleAssignmentPolicy( + name="Policy2", + id="id-policy2", + assigned_roles=["My Custom Apps", "My Voice Mail"], + ) + ] + + check = exchange_roles_assignment_policy_addins_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Role assignment policy 'Policy2' allows Outlook add-ins via roles: My Custom Apps." + ) + assert result[0].resource_name == "Policy2" + assert result[0].resource_id == "id-policy2" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.role_assignment_policies[0].dict() + ) diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 73cf90c6d9..0aa484aab0 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -9,6 +9,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( MailboxAuditProperties, MailboxPolicy, Organization, + RoleAssignmentPolicy, TransportConfig, TransportRule, ) @@ -75,6 +76,27 @@ def mock_exchange_get_mailbox_policy(_): ) +def mock_exchange_get_role_assignment_policies(_): + return [ + RoleAssignmentPolicy( + name="Default Role Assignment Policy", + id="12345678-1234-1234-1234", + assigned_roles=[ + "MyProfileInformation", + "MyDistributionGroupMembership", + "MyRetentionPolicies", + "MyDistributionGroups", + "MyVoiceMail", + ], + ), + RoleAssignmentPolicy( + name="Test Policy", + id="12345678-1234-1234", + assigned_roles=[], + ), + ] + + def mock_exchange_get_mailbox_audit_properties(_): return [ MailboxAuditProperties( @@ -345,3 +367,35 @@ class Test_Exchange_Service: assert mailbox_audit_properties[0].audit_log_age == 90 assert mailbox_audit_properties[0].identity == "test" exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_role_assignment_policies", + new=mock_exchange_get_role_assignment_policies, + ) + def test_get_role_assignment_policies(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + role_assignment_policies = exchange_client.role_assignment_policies + assert len(role_assignment_policies) == 2 + assert role_assignment_policies[0].name == "Default Role Assignment Policy" + assert role_assignment_policies[0].id == "12345678-1234-1234-1234" + assert role_assignment_policies[0].assigned_roles == [ + "MyProfileInformation", + "MyDistributionGroupMembership", + "MyRetentionPolicies", + "MyDistributionGroups", + "MyVoiceMail", + ] + assert role_assignment_policies[1].name == "Test Policy" + assert role_assignment_policies[1].id == "12345678-1234-1234" + assert role_assignment_policies[1].assigned_roles == [] + + exchange_client.powershell.close() From c938a2569322e5ef804490c4032833433f2bd4f0 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 12:44:39 +0200 Subject: [PATCH 242/359] feat(exchange): add new check `exchange_organization_modern_authentication_enabled` (#7636) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...odern_authentication_enabled.metadata.json | 30 ++++ ...anization_modern_authentication_enabled.py | 46 +++++++ .../services/exchange/exchange_service.py | 4 + ...anization_mailbox_auditing_enabled_test.py | 2 + ...ange_organization_mailtips_enabled_test.py | 2 + ...tion_modern_authentication_enabled_test.py | 130 ++++++++++++++++++ .../exchange/exchange_service_test.py | 2 + 9 files changed, 217 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 19426c4e10..fc76ec6948 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_presenters_restricted` [(#7613)](https://github.com/prowler-cloud/prowler/pull/7613) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) +- Add new check for Modern Authentication enabled for Exchange Online in M365 [(#7636)](https://github.com/prowler-cloud/prowler/pull/7636) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) - Add new check for Roles Assignment Policy with no AddIns for Exchange in M365 [(#7644)](https://github.com/prowler-cloud/prowler/pull/7644) diff --git a/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.metadata.json new file mode 100644 index 0000000000..b78cd9cf19 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_organization_modern_authentication_enabled", + "CheckTitle": "Ensure Modern Authentication for Exchange Online is enabled.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Exchange Organization Configuration", + "Description": "Ensure that modern authentication is enabled for Exchange Online, requiring exchange and mailboxes clients to use strong authentication mechanisms instead of basic authentication.", + "Risk": "If modern authentication is not enabled, Exchange Online email clients may fall back to basic authentication, making it easier for attackers to bypass multifactor authentication and compromise user credentials.", + "RelatedUrl": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/enable-or-disable-modern-authentication-in-exchange-online", + "Remediation": { + "Code": { + "CLI": "Set-OrganizationConfig -OAuth2ClientProfileEnabled $True", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable modern authentication in Exchange Online to enforce secure authentication methods for email clients.", + "Url": "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/enable-or-disable-modern-authentication-in-exchange-online" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.py b/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.py new file mode 100644 index 0000000000..93b13d133d --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled.py @@ -0,0 +1,46 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client + + +class exchange_organization_modern_authentication_enabled(Check): + """ + Check if Modern Authentication is enabled for Exchange Online. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check for Modern Authentication in Exchange Online. + + This method checks if Modern Authentication is enabled in the Exchange organization configuration. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + organization_config = exchange_client.organization_config + if organization_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=organization_config, + resource_name=organization_config.name, + resource_id=organization_config.guid, + ) + report.status = "FAIL" + report.status_extended = ( + "Modern Authentication is not enabled for Exchange Online." + ) + + if organization_config.oauth_enabled: + report.status = "PASS" + report.status_extended = ( + "Modern Authentication is enabled for Exchange Online." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index af2ecbce03..67f0564e74 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -44,6 +44,9 @@ class Exchange(M365Service): audit_disabled=organization_configuration.get( "AuditDisabled", False ), + oauth_enabled=organization_configuration.get( + "OAuth2ClientProfileEnabled", True + ), mailtips_enabled=organization_configuration.get( "MailTipsAllTipsEnabled", True ), @@ -235,6 +238,7 @@ class Organization(BaseModel): name: str guid: str audit_disabled: bool + oauth_enabled: bool mailtips_enabled: bool mailtips_external_recipient_enabled: bool mailtips_group_metrics_enabled: bool diff --git a/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py index 82860f3b7d..374c8a42c9 100644 --- a/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py +++ b/tests/providers/m365/services/exchange/exchange_organization_mailbox_auditing_enabled/exchange_organization_mailbox_auditing_enabled_test.py @@ -60,6 +60,7 @@ class Test_exchange_organization_mailbox_auditing_enabled: audit_disabled=True, name="test", guid="test", + oauth_enabled=True, mailtips_enabled=True, mailtips_external_recipient_enabled=True, mailtips_group_metrics_enabled=True, @@ -108,6 +109,7 @@ class Test_exchange_organization_mailbox_auditing_enabled: audit_disabled=False, name="test", guid="test", + oauth_enabled=True, mailtips_enabled=True, mailtips_external_recipient_enabled=True, mailtips_group_metrics_enabled=True, diff --git a/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py index cbcc6266c5..d3355b7f3e 100644 --- a/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py +++ b/tests/providers/m365/services/exchange/exchange_organization_mailtips_enabled/exchange_organization_mailtips_enabled_test.py @@ -64,6 +64,7 @@ class Test_exchange_organization_mailtips_enabled: name="test-org", guid="org-guid", audit_disabled=False, + oauth_enabled=True, mailtips_enabled=False, mailtips_external_recipient_enabled=False, mailtips_group_metrics_enabled=True, @@ -116,6 +117,7 @@ class Test_exchange_organization_mailtips_enabled: name="test-org", guid="org-guid", audit_disabled=False, + oauth_enabled=True, mailtips_enabled=True, mailtips_external_recipient_enabled=True, mailtips_group_metrics_enabled=True, diff --git a/tests/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled_test.py b/tests/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled_test.py new file mode 100644 index 0000000000..419453c397 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_organization_modern_authentication_enabled/exchange_organization_modern_authentication_enabled_test.py @@ -0,0 +1,130 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_organization_modern_authentication_enabled: + def test_no_organization(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + exchange_client.organization_config = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled import ( + exchange_organization_modern_authentication_enabled, + ) + + check = exchange_organization_modern_authentication_enabled() + result = check.execute() + assert len(result) == 0 + + def test_modern_authentication_disabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled import ( + exchange_organization_modern_authentication_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.organization_config = Organization( + oauth_enabled=False, + name="test", + guid="test", + audit_disabled=False, + mailtips_enabled=False, + mailtips_external_recipient_enabled=False, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, + ) + + check = exchange_organization_modern_authentication_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Modern Authentication is not enabled for Exchange Online." + ) + assert result[0].resource == exchange_client.organization_config.dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" + + def test_modern_authentication_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_organization_modern_authentication_enabled.exchange_organization_modern_authentication_enabled import ( + exchange_organization_modern_authentication_enabled, + ) + from prowler.providers.m365.services.exchange.exchange_service import ( + Organization, + ) + + exchange_client.organization_config = Organization( + oauth_enabled=True, + name="test", + guid="test", + audit_disabled=False, + mailtips_enabled=False, + mailtips_external_recipient_enabled=False, + mailtips_group_metrics_enabled=True, + mailtips_large_audience_threshold=25, + ) + + check = exchange_organization_modern_authentication_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Modern Authentication is enabled for Exchange Online." + ) + assert result[0].resource == exchange_client.organization_config.dict() + assert result[0].resource_name == "test" + assert result[0].resource_id == "test" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 0aa484aab0..afeb326e46 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -21,6 +21,7 @@ def mock_exchange_get_organization_config(_): audit_disabled=True, name="test", guid="test", + oauth_enabled=True, mailtips_enabled=True, mailtips_external_recipient_enabled=False, mailtips_group_metrics_enabled=True, @@ -183,6 +184,7 @@ class Test_Exchange_Service: assert organization_config.name == "test" assert organization_config.guid == "test" assert organization_config.audit_disabled is True + assert organization_config.oauth_enabled is True assert organization_config.mailtips_enabled is True assert organization_config.mailtips_external_recipient_enabled is False assert organization_config.mailtips_group_metrics_enabled is True From 9828824b737b8deda61f4a6646b54e0ad45033b9 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Mon, 5 May 2025 10:38:57 +0200 Subject: [PATCH 243/359] chore(sentry): attach stacktrace to logging events (#7598) 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 --- api/README.md | 1 + api/src/backend/config/settings/sentry.py | 2 ++ docs/index.md | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/README.md b/api/README.md index 063d8342f6..a1241372ca 100644 --- a/api/README.md +++ b/api/README.md @@ -235,6 +235,7 @@ To view the logs for any component (e.g., Django, Celery worker), you can use th ```console docker logs -f $(docker ps --format "{{.Names}}" | grep 'api-') +``` ## Applying migrations diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py index bf354b90e5..87d08bd6ee 100644 --- a/api/src/backend/config/settings/sentry.py +++ b/api/src/backend/config/settings/sentry.py @@ -97,4 +97,6 @@ sentry_sdk.init( # possible. "continuous_profiling_auto_start": True, }, + attach_stacktrace=True, + ignore_errors=IGNORED_EXCEPTIONS, ) diff --git a/docs/index.md b/docs/index.md index ff63c9fd02..1645b3d4fc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -53,7 +53,7 @@ Prowler App can be installed in different ways, depending on your environment: You can change the environment variables in the `.env` file. Note that it is not recommended to use the default values in production environments. ???+ note - There is a development mode available, you can use the file https://github.com/prowler-cloud/prowler/blob/master/docker-compose.dev.yml to run the app in development mode. + There is a development mode available, you can use the file https://github.com/prowler-cloud/prowler/blob/master/docker-compose-dev.yml to run the app in development mode. ???+ warning Google and GitHub authentication is only available in [Prowler Cloud](https://prowler.com). From 180eb61feebfce6217b9e61663f8ed721e90af4c Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Mon, 5 May 2025 12:23:04 +0200 Subject: [PATCH 244/359] fix: error about page number persistence when filters change (#7655) --- ui/components/filters/custom-date-picker.tsx | 14 ++-- ui/components/filters/custom-search-input.tsx | 17 +++-- ui/components/filters/filter-controls.tsx | 17 ++--- .../ui/custom/custom-dropdown-filter.tsx | 13 ++-- .../ui/table/data-table-filter-custom.tsx | 18 ++--- ui/hooks/use-url-filters.ts | 68 +++++++++++++++++++ 6 files changed, 97 insertions(+), 50 deletions(-) create mode 100644 ui/hooks/use-url-filters.ts diff --git a/ui/components/filters/custom-date-picker.tsx b/ui/components/filters/custom-date-picker.tsx index 7b39d6a6d8..cf2950d7f2 100644 --- a/ui/components/filters/custom-date-picker.tsx +++ b/ui/components/filters/custom-date-picker.tsx @@ -8,12 +8,14 @@ import { } from "@internationalized/date"; import { Button, ButtonGroup, DatePicker } from "@nextui-org/react"; import { useLocale } from "@react-aria/i18n"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useSearchParams } from "next/navigation"; import React, { useCallback, useEffect, useRef } from "react"; +import { useUrlFilters } from "@/hooks/use-url-filters"; + export const CustomDatePicker = () => { - const router = useRouter(); const searchParams = useSearchParams(); + const { updateFilter } = useUrlFilters(); const [value, setValue] = React.useState(() => { const dateParam = searchParams.get("filter[inserted_at]"); @@ -28,15 +30,13 @@ export const CustomDatePicker = () => { const applyDateFilter = useCallback( (date: any) => { - const params = new URLSearchParams(searchParams.toString()); if (date) { - params.set("filter[inserted_at]", date.toString()); + updateFilter("inserted_at", date.toString()); } else { - params.delete("filter[inserted_at]"); + updateFilter("inserted_at", null); } - router.push(`?${params.toString()}`, { scroll: false }); }, - [router, searchParams], + [updateFilter], ); const initialRender = useRef(true); diff --git a/ui/components/filters/custom-search-input.tsx b/ui/components/filters/custom-search-input.tsx index 14d23bd812..0048236cc9 100644 --- a/ui/components/filters/custom-search-input.tsx +++ b/ui/components/filters/custom-search-input.tsx @@ -1,26 +1,25 @@ import { Input } from "@nextui-org/react"; import debounce from "lodash.debounce"; import { SearchIcon, XCircle } from "lucide-react"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useSearchParams } from "next/navigation"; import React, { useCallback, useEffect, useState } from "react"; -export const CustomSearchInput: React.FC = () => { - const router = useRouter(); - const searchParams = useSearchParams(); +import { useUrlFilters } from "@/hooks/use-url-filters"; +export const CustomSearchInput: React.FC = () => { + const searchParams = useSearchParams(); + const { updateFilter } = useUrlFilters(); const [searchQuery, setSearchQuery] = useState(""); const applySearch = useCallback( (query: string) => { - const params = new URLSearchParams(searchParams.toString()); if (query) { - params.set("filter[search]", query); + updateFilter("search", query); } else { - params.delete("filter[search]"); + updateFilter("search", null); } - router.push(`?${params.toString()}`, { scroll: false }); }, - [router, searchParams], + [updateFilter], ); const debouncedChangeHandler = useCallback( diff --git a/ui/components/filters/filter-controls.tsx b/ui/components/filters/filter-controls.tsx index 7a41bc37d5..35dddb0b37 100644 --- a/ui/components/filters/filter-controls.tsx +++ b/ui/components/filters/filter-controls.tsx @@ -1,8 +1,9 @@ "use client"; -import { useRouter, useSearchParams } from "next/navigation"; -import React, { useCallback, useEffect, useState } from "react"; +import { useSearchParams } from "next/navigation"; +import React, { useEffect, useState } from "react"; +import { useUrlFilters } from "@/hooks/use-url-filters"; import { FilterControlsProps } from "@/types"; import { CrossIcon } from "../icons"; @@ -24,8 +25,8 @@ export const FilterControls: React.FC = ({ mutedFindings = false, customFilters, }) => { - const router = useRouter(); const searchParams = useSearchParams(); + const { clearAllFilters } = useUrlFilters(); const [showClearButton, setShowClearButton] = useState(false); useEffect(() => { @@ -35,16 +36,6 @@ export const FilterControls: React.FC = ({ setShowClearButton(hasFilters); }, [searchParams]); - const clearAllFilters = useCallback(() => { - const params = new URLSearchParams(searchParams.toString()); - Array.from(params.keys()).forEach((key) => { - if (key.startsWith("filter[") || key === "sort") { - params.delete(key); - } - }); - router.push(`?${params.toString()}`, { scroll: false }); - }, [router, searchParams]); - return (
    diff --git a/ui/components/ui/custom/custom-dropdown-filter.tsx b/ui/components/ui/custom/custom-dropdown-filter.tsx index 8fc213f75f..7f659d9c13 100644 --- a/ui/components/ui/custom/custom-dropdown-filter.tsx +++ b/ui/components/ui/custom/custom-dropdown-filter.tsx @@ -11,10 +11,11 @@ import { ScrollShadow, } from "@nextui-org/react"; import { XCircle } from "lucide-react"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useSearchParams } from "next/navigation"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { PlusCircleIcon } from "@/components/icons"; +import { useUrlFilters } from "@/hooks/use-url-filters"; import { CustomDropdownFilterProps } from "@/types"; const filterSelectedClass = @@ -24,8 +25,8 @@ export const CustomDropdownFilter: React.FC = ({ filter, onFilterChange, }) => { - const router = useRouter(); const searchParams = useSearchParams(); + const { clearFilter } = useUrlFilters(); const [groupSelected, setGroupSelected] = useState(new Set()); const [pendingClearFilter, setPendingClearFilter] = useState( null, @@ -114,13 +115,11 @@ export const CustomDropdownFilter: React.FC = ({ // Execute the update in the router after the render useEffect(() => { - if (pendingClearFilter) { - const params = new URLSearchParams(searchParams.toString()); - params.delete(`filter[${pendingClearFilter}]`); - router.push(`?${params.toString()}`, { scroll: false }); + if (pendingClearFilter && filter) { + clearFilter(pendingClearFilter); setPendingClearFilter(null); // Reset the state } - }, [pendingClearFilter, searchParams, router]); + }, [pendingClearFilter, clearFilter, filter]); return (
    diff --git a/ui/components/ui/table/data-table-filter-custom.tsx b/ui/components/ui/table/data-table-filter-custom.tsx index 3ef0c0d330..655297659c 100644 --- a/ui/components/ui/table/data-table-filter-custom.tsx +++ b/ui/components/ui/table/data-table-filter-custom.tsx @@ -1,11 +1,11 @@ "use client"; -import { useRouter, useSearchParams } from "next/navigation"; import React, { useState } from "react"; import { useCallback } from "react"; import { CustomFilterIcon } from "@/components/icons"; import { CustomButton, CustomDropdownFilter } from "@/components/ui/custom"; +import { useUrlFilters } from "@/hooks/use-url-filters"; import { FilterOption } from "@/types"; export interface DataTableFilterCustomProps { @@ -17,24 +17,14 @@ export const DataTableFilterCustom = ({ filters, defaultOpen = false, }: DataTableFilterCustomProps) => { - const router = useRouter(); - const searchParams = useSearchParams(); + const { updateFilter } = useUrlFilters(); const [showFilters, setShowFilters] = useState(defaultOpen); const pushDropdownFilter = useCallback( (key: string, values: string[]) => { - const params = new URLSearchParams(searchParams); - const filterKey = `filter[${key}]`; - - if (values.length === 0) { - params.delete(filterKey); - } else { - params.set(filterKey, values.join(",")); - } - - router.push(`?${params.toString()}`); + updateFilter(key, values.length > 0 ? values : null); }, - [router, searchParams], + [updateFilter], ); return ( diff --git a/ui/hooks/use-url-filters.ts b/ui/hooks/use-url-filters.ts new file mode 100644 index 0000000000..c29de37327 --- /dev/null +++ b/ui/hooks/use-url-filters.ts @@ -0,0 +1,68 @@ +"use client"; + +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useCallback } from "react"; + +/** + * Custom hook to handle URL filters and automatically reset + * pagination when filters change. + */ +export const useUrlFilters = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const pathname = usePathname(); + + const updateFilter = useCallback( + (key: string, value: string | string[] | null) => { + const params = new URLSearchParams(searchParams.toString()); + + // Always reset page to 1 when a filter is applied + params.set("page", "1"); + + const filterKey = key.startsWith("filter[") ? key : `filter[${key}]`; + + if (value === null || (Array.isArray(value) && value.length === 0)) { + params.delete(filterKey); + } else if (Array.isArray(value)) { + params.set(filterKey, value.join(",")); + } else { + params.set(filterKey, value); + } + + router.push(`${pathname}?${params.toString()}`, { scroll: false }); + }, + [router, searchParams, pathname], + ); + + const clearFilter = useCallback( + (key: string) => { + const params = new URLSearchParams(searchParams.toString()); + const filterKey = key.startsWith("filter[") ? key : `filter[${key}]`; + + params.delete(filterKey); + params.set("page", "1"); + + router.push(`${pathname}?${params.toString()}`, { scroll: false }); + }, + [router, searchParams, pathname], + ); + + const clearAllFilters = useCallback(() => { + const params = new URLSearchParams(searchParams.toString()); + Array.from(params.keys()).forEach((key) => { + if (key.startsWith("filter[") || key === "sort") { + params.delete(key); + } + }); + + params.delete("page"); + + router.push(`${pathname}?${params.toString()}`, { scroll: false }); + }, [router, searchParams, pathname]); + + return { + updateFilter, + clearFilter, + clearAllFilters, + }; +}; From 44f8e4c488a6e2e861da4e5410621b987d8b8dc6 Mon Sep 17 00:00:00 2001 From: sumit-tft <70506234+sumit-tft@users.noreply.github.com> Date: Mon, 5 May 2025 19:12:06 +0530 Subject: [PATCH 245/359] feat(ui): Page size for datatables (#7634) --- ui/actions/invitations/invitation.ts | 2 + ui/actions/manage-groups/manage-groups.ts | 3 ++ ui/actions/providers/providers.ts | 2 + ui/actions/roles/roles.ts | 2 + ui/actions/scans/scans.ts | 2 + ui/actions/users/users.ts | 2 + ui/app/(prowler)/findings/page.tsx | 3 +- ui/app/(prowler)/invitations/page.tsx | 9 +++- ui/app/(prowler)/manage-groups/page.tsx | 2 + ui/app/(prowler)/providers/page.tsx | 9 +++- ui/app/(prowler)/roles/page.tsx | 3 +- ui/app/(prowler)/scans/page.tsx | 3 +- ui/app/(prowler)/users/page.tsx | 3 +- .../ui/table/data-table-pagination.tsx | 51 +++++++++++++++++-- ui/components/ui/table/data-table.tsx | 1 + ui/lib/helper.ts | 5 +- ui/types/components.ts | 1 + 17 files changed, 93 insertions(+), 10 deletions(-) diff --git a/ui/actions/invitations/invitation.ts b/ui/actions/invitations/invitation.ts index 6211ed5a06..44cbd1a455 100644 --- a/ui/actions/invitations/invitation.ts +++ b/ui/actions/invitations/invitation.ts @@ -15,6 +15,7 @@ export const getInvitations = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -23,6 +24,7 @@ export const getInvitations = async ({ const url = new URL(`${apiBaseUrl}/tenants/invitations`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/manage-groups/manage-groups.ts b/ui/actions/manage-groups/manage-groups.ts index 118ab1704e..f2b1ca7289 100644 --- a/ui/actions/manage-groups/manage-groups.ts +++ b/ui/actions/manage-groups/manage-groups.ts @@ -16,11 +16,13 @@ export const getProviderGroups = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }: { page?: number; query?: string; sort?: string; filters?: Record; + pageSize?: number; }): Promise => { const headers = await getAuthHeaders({ contentType: false }); @@ -29,6 +31,7 @@ export const getProviderGroups = async ({ const url = new URL(`${apiBaseUrl}/provider-groups`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 6dbb3a0aee..2a36f7ca05 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -16,6 +16,7 @@ export const getProviders = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -24,6 +25,7 @@ export const getProviders = async ({ const url = new URL(`${apiBaseUrl}/providers?include=provider_groups`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index 94dd92d270..e63558d1b9 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -15,6 +15,7 @@ export const getRoles = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -23,6 +24,7 @@ export const getRoles = async ({ const url = new URL(`${apiBaseUrl}/roles`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/scans/scans.ts b/ui/actions/scans/scans.ts index 0871bded69..81ded7e469 100644 --- a/ui/actions/scans/scans.ts +++ b/ui/actions/scans/scans.ts @@ -15,6 +15,7 @@ export const getScans = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -23,6 +24,7 @@ export const getScans = async ({ const url = new URL(`${apiBaseUrl}/scans`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/actions/users/users.ts b/ui/actions/users/users.ts index af688877bd..b826c5fcc7 100644 --- a/ui/actions/users/users.ts +++ b/ui/actions/users/users.ts @@ -15,6 +15,7 @@ export const getUsers = async ({ query = "", sort = "", filters = {}, + pageSize = 10, }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -23,6 +24,7 @@ export const getUsers = async ({ const url = new URL(`${apiBaseUrl}/users?include=roles`); if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index 9fa50fc115..6166ed4f94 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -149,6 +149,7 @@ const SSRDataTable = async ({ searchParams: SearchParamsProps; }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); const defaultSort = "severity,status,-inserted_at"; const sort = searchParams.sort?.toString() || defaultSort; @@ -186,7 +187,7 @@ const SSRDataTable = async ({ page, sort: encodedSort, filters, - pageSize: 10, + pageSize, }); // Create dictionaries for resources, scans, and providers diff --git a/ui/app/(prowler)/invitations/page.tsx b/ui/app/(prowler)/invitations/page.tsx index b51a315d15..89a7776b13 100644 --- a/ui/app/(prowler)/invitations/page.tsx +++ b/ui/app/(prowler)/invitations/page.tsx @@ -44,6 +44,7 @@ const SSRDataTable = async ({ }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); const sort = searchParams.sort?.toString(); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); // Extract all filter parameters const filters = Object.fromEntries( @@ -54,7 +55,13 @@ const SSRDataTable = async ({ const query = (filters["filter[search]"] as string) || ""; // Fetch invitations and roles - const invitationsData = await getInvitations({ query, page, sort, filters }); + const invitationsData = await getInvitations({ + query, + page, + sort, + filters, + pageSize, + }); const rolesData = await getRoles({}); // Create a dictionary for roles by invitation ID diff --git a/ui/app/(prowler)/manage-groups/page.tsx b/ui/app/(prowler)/manage-groups/page.tsx index 62b3c83342..178baf320e 100644 --- a/ui/app/(prowler)/manage-groups/page.tsx +++ b/ui/app/(prowler)/manage-groups/page.tsx @@ -163,6 +163,7 @@ const SSRDataTable = async ({ }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); const sort = searchParams.sort?.toString(); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); // Convert filters to the correct type const filters: Record = {}; @@ -178,6 +179,7 @@ const SSRDataTable = async ({ page, sort, filters, + pageSize, }); return ( { const page = parseInt(searchParams.page?.toString() || "1", 10); const sort = searchParams.sort?.toString(); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); // Extract all filter parameters const filters = Object.fromEntries( @@ -59,7 +60,13 @@ const SSRDataTable = async ({ // Extract query from filters const query = (filters["filter[search]"] as string) || ""; - const providersData = await getProviders({ query, page, sort, filters }); + const providersData = await getProviders({ + query, + page, + sort, + filters, + pageSize, + }); const providerGroupDict = providersData?.included diff --git a/ui/app/(prowler)/roles/page.tsx b/ui/app/(prowler)/roles/page.tsx index f0515ea546..d613990d98 100644 --- a/ui/app/(prowler)/roles/page.tsx +++ b/ui/app/(prowler)/roles/page.tsx @@ -41,6 +41,7 @@ const SSRDataTable = async ({ }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); const sort = searchParams.sort?.toString(); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); // Extract all filter parameters const filters = Object.fromEntries( @@ -50,7 +51,7 @@ const SSRDataTable = async ({ // Extract query from filters const query = (filters["filter[search]"] as string) || ""; - const rolesData = await getRoles({ query, page, sort, filters }); + const rolesData = await getRoles({ query, page, sort, filters, pageSize }); return ( { const page = parseInt(searchParams.page?.toString() || "1", 10); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); const sort = searchParams.sort?.toString(); // Extract all filter parameters, excluding scanId @@ -120,7 +121,7 @@ const SSRDataTableScans = async ({ const query = (filters["filter[search]"] as string) || ""; // Fetch scans data - const scansData = await getScans({ query, page, sort, filters }); + const scansData = await getScans({ query, page, sort, filters, pageSize }); // Handle expanded scans data const expandedScansData = await Promise.all( diff --git a/ui/app/(prowler)/users/page.tsx b/ui/app/(prowler)/users/page.tsx index b4a19ac5fc..d6bbe6152f 100644 --- a/ui/app/(prowler)/users/page.tsx +++ b/ui/app/(prowler)/users/page.tsx @@ -41,6 +41,7 @@ const SSRDataTable = async ({ }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); const sort = searchParams.sort?.toString(); + const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); // Extract all filter parameters const filters = Object.fromEntries( @@ -50,7 +51,7 @@ const SSRDataTable = async ({ // Extract query from filters const query = (filters["filter[search]"] as string) || ""; - const usersData = await getUsers({ query, page, sort, filters }); + const usersData = await getUsers({ query, page, sort, filters, pageSize }); const rolesData = await getRoles({}); // Create a dictionary for roles by user ID diff --git a/ui/components/ui/table/data-table-pagination.tsx b/ui/components/ui/table/data-table-pagination.tsx index c81e272100..a7773925e9 100644 --- a/ui/components/ui/table/data-table-pagination.tsx +++ b/ui/components/ui/table/data-table-pagination.tsx @@ -7,23 +7,36 @@ import { DoubleArrowRightIcon, } from "@radix-ui/react-icons"; import Link from "next/link"; -import { usePathname, useSearchParams } from "next/navigation"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useState } from "react"; import { getPaginationInfo } from "@/lib"; import { MetaDataProps } from "@/types"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "../select/Select"; + interface DataTablePaginationProps { - pageSizeOptions?: number[]; metadata?: MetaDataProps; } export function DataTablePagination({ metadata }: DataTablePaginationProps) { const pathname = usePathname(); const searchParams = useSearchParams(); + const router = useRouter(); + const initialPageSize = searchParams.get("pageSize") ?? "10"; + + const [selectedPageSize, setSelectedPageSize] = useState(initialPageSize); if (!metadata) return null; - const { currentPage, totalPages, totalEntries } = getPaginationInfo(metadata); + const { currentPage, totalPages, totalEntries, itemsPerPageOptions } = + getPaginationInfo(metadata); const createPageUrl = (pageNumber: number | string) => { const params = new URLSearchParams(searchParams); @@ -44,6 +57,38 @@ export function DataTablePagination({ metadata }: DataTablePaginationProps) { {totalEntries} entries in Total.
    + {/* Rows per page selector */} +
    +

    Rows per page

    + +
    Page {currentPage} of {totalPages}
    diff --git a/ui/components/ui/table/data-table.tsx b/ui/components/ui/table/data-table.tsx index 4577f1bf08..b759e4316d 100644 --- a/ui/components/ui/table/data-table.tsx +++ b/ui/components/ui/table/data-table.tsx @@ -48,6 +48,7 @@ export function DataTable({ getSortedRowModel: getSortedRowModel(), onColumnFiltersChange: setColumnFilters, getFilteredRowModel: getFilteredRowModel(), + manualPagination: true, state: { sorting, columnFilters, diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index e8e7a9e71c..94da6e948e 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -161,8 +161,11 @@ export const getPaginationInfo = (metadata: MetaDataProps) => { const currentPage = metadata?.pagination.page ?? "1"; const totalPages = metadata?.pagination.pages; const totalEntries = metadata?.pagination.count; + const itemsPerPageOptions = metadata?.pagination.itemsPerPage ?? [ + 10, 20, 30, 50, 100, + ]; - return { currentPage, totalPages, totalEntries }; + return { currentPage, totalPages, totalEntries, itemsPerPageOptions }; }; export function encryptKey(passkey: string) { diff --git a/ui/types/components.ts b/ui/types/components.ts index b9a9453690..606c0fe0ba 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -755,6 +755,7 @@ export interface MetaDataProps { page: number; pages: number; count: number; + itemsPerPage?: Array; }; version: string; } From 844dd5ba958719ff4db3f0bc3498a069b60a80d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 09:53:40 -0400 Subject: [PATCH 246/359] chore(deps): bump actions/setup-python from 5.5.0 to 5.6.0 (#7647) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-build-lint-push-containers.yml | 2 +- .github/workflows/sdk-pull-request.yml | 2 +- .github/workflows/sdk-pypi-release.yml | 2 +- .github/workflows/sdk-refresh-aws-services-regions.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 49df46c8e5..178e91d7a5 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -94,7 +94,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml index e29d91604e..28f935c0be 100644 --- a/.github/workflows/sdk-build-lint-push-containers.yml +++ b/.github/workflows/sdk-build-lint-push-containers.yml @@ -62,7 +62,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Python - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 484df4e10a..65986ea7fa 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -51,7 +51,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} cache: "poetry" diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml index e2183909e5..07d6ca5a6f 100644 --- a/.github/workflows/sdk-pypi-release.yml +++ b/.github/workflows/sdk-pypi-release.yml @@ -71,7 +71,7 @@ jobs: pipx install poetry==2.1.1 - name: Setup Python - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} # cache: ${{ env.CACHE }} diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml index cc0fdab1e1..8ebc1b5db0 100644 --- a/.github/workflows/sdk-refresh-aws-services-regions.yml +++ b/.github/workflows/sdk-refresh-aws-services-regions.yml @@ -28,7 +28,7 @@ jobs: ref: ${{ env.GITHUB_BRANCH }} - name: setup python - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: 3.9 #install the python needed From a580b1ee04d10f84cd67bb702ef9a2e31f516fa1 Mon Sep 17 00:00:00 2001 From: drewadwade <32397380+drewadwade@users.noreply.github.com> Date: Mon, 5 May 2025 09:53:55 -0400 Subject: [PATCH 247/359] fix(azure): CIS v2.0 4.4.1 Uses Wrong Check (#7656) Co-authored-by: pedrooot --- prowler/CHANGELOG.md | 1 + prowler/compliance/azure/cis_2.0_azure.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index fc76ec6948..eaeb7d4812 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -55,6 +55,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) - Remove first empty line in HTML output [(#7606)](https://github.com/prowler-cloud/prowler/pull/7606) - Ensure that ContentType in upload_file matches the uploaded file’s format [(#7635)](https://github.com/prowler-cloud/prowler/pull/7635) +- Fix incorrect check inside 4.4.1 requirement for Azure CIS 2.0 [(#7656)](https://github.com/prowler-cloud/prowler/pull/7656). --- diff --git a/prowler/compliance/azure/cis_2.0_azure.json b/prowler/compliance/azure/cis_2.0_azure.json index 6a35609d3e..59ab14879d 100644 --- a/prowler/compliance/azure/cis_2.0_azure.json +++ b/prowler/compliance/azure/cis_2.0_azure.json @@ -1988,7 +1988,7 @@ "Id": "4.4.1", "Description": "Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server", "Checks": [ - "postgresql_flexible_server_allow_access_services_disabled" + "mysql_flexible_server_ssl_connection_enabled" ], "Attributes": [ { From 473631f83be7796f3f583352fe1509731440cbda Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 09:54:16 -0400 Subject: [PATCH 248/359] chore(deps): bump trufflesecurity/trufflehog from 3.88.23 to 3.88.26 (#7648) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/find-secrets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml index 4043f22b7d..a6240297b6 100644 --- a/.github/workflows/find-secrets.yml +++ b/.github/workflows/find-secrets.yml @@ -11,7 +11,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@690e5c7aff8347c3885096f3962a0633d9129607 # v3.88.23 + uses: trufflesecurity/trufflehog@b06f6d72a3791308bb7ba59c2b8cb7a083bd17e4 # v3.88.26 with: path: ./ base: ${{ github.event.repository.default_branch }} From d5ab72a97c32b50245964fa593ca31e37f68d2bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 09:54:34 -0400 Subject: [PATCH 249/359] chore(deps): bump github/codeql-action from 3.28.15 to 3.28.16 (#7649) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-codeql.yml | 4 ++-- .github/workflows/sdk-codeql.yml | 4 ++-- .github/workflows/ui-codeql.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml index df5c1456a1..95b044007b 100644 --- a/.github/workflows/api-codeql.yml +++ b/.github/workflows/api-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/api-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml index ac48ea1163..5634ead1e6 100644 --- a/.github/workflows/sdk-codeql.yml +++ b/.github/workflows/sdk-codeql.yml @@ -56,12 +56,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/sdk-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml index 29d1fe600d..a43f59c245 100644 --- a/.github/workflows/ui-codeql.yml +++ b/.github/workflows/ui-codeql.yml @@ -48,12 +48,12 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/ui-codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: category: "/language:${{matrix.language}}" From e6d48c1fa4369252654a9866c0324f70ecc9a148 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 5 May 2025 15:56:16 +0200 Subject: [PATCH 250/359] chore(regions_update): Changes in regions for AWS services (#7657) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- .../providers/aws/aws_regions_by_service.json | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 210a12a965..535c7e8aa0 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -821,6 +821,7 @@ "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", @@ -2801,6 +2802,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -2814,6 +2816,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -3445,6 +3448,16 @@ ] } }, + "dsql": { + "regions": { + "aws": [ + "us-east-1", + "us-east-2" + ], + "aws-cn": [], + "aws-us-gov": [] + } + }, "dynamodb": { "regions": { "aws": [ @@ -8769,6 +8782,7 @@ "ap-northeast-1", "ap-northeast-2", "ap-south-1", + "ap-south-2", "ap-southeast-1", "ap-southeast-2", "ap-southeast-3", @@ -9280,7 +9294,10 @@ "us-west-1", "us-west-2" ], - "aws-cn": [], + "aws-cn": [ + "cn-north-1", + "cn-northwest-1" + ], "aws-us-gov": [ "us-gov-east-1", "us-gov-west-1" @@ -9634,6 +9651,8 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", + "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -9647,6 +9666,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -9849,6 +9869,7 @@ "aws": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", @@ -9856,6 +9877,8 @@ "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-2" @@ -10225,6 +10248,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -10238,6 +10262,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -11106,6 +11131,13 @@ "aws-us-gov": [] } }, + "timestream-query": { + "regions": { + "aws": [], + "aws-cn": [], + "aws-us-gov": [] + } + }, "timestream-write": { "regions": { "aws": [ From ae74cab70ab4418542451e44acf5178cd6560cf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 09:58:38 -0400 Subject: [PATCH 251/359] chore(deps): bump docker/build-push-action from 6.15.0 to 6.16.0 (#7650) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-build-lint-push-containers.yml | 4 ++-- .github/workflows/api-pull-request.yml | 2 +- .github/workflows/sdk-build-lint-push-containers.yml | 4 ++-- .github/workflows/ui-build-lint-push-containers.yml | 4 ++-- .github/workflows/ui-pull-request.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/api-build-lint-push-containers.yml b/.github/workflows/api-build-lint-push-containers.yml index 4a24e47031..953bd032f1 100644 --- a/.github/workflows/api-build-lint-push-containers.yml +++ b/.github/workflows/api-build-lint-push-containers.yml @@ -81,7 +81,7 @@ jobs: - name: Build and push container image (latest) # Comment the following line for testing if: github.event_name == 'push' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.WORKING_DIRECTORY }} # Set push: false for testing @@ -94,7 +94,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.WORKING_DIRECTORY }} push: true diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml index 178e91d7a5..675c0ae500 100644 --- a/.github/workflows/api-pull-request.yml +++ b/.github/workflows/api-pull-request.yml @@ -179,7 +179,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build Container - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.API_WORKING_DIR }} push: false diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml index 28f935c0be..f4314055ae 100644 --- a/.github/workflows/sdk-build-lint-push-containers.yml +++ b/.github/workflows/sdk-build-lint-push-containers.yml @@ -127,7 +127,7 @@ jobs: - name: Build and push container image (latest) if: github.event_name == 'push' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: push: true tags: | @@ -140,7 +140,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: # Use local context to get changes # https://github.com/docker/build-push-action#path-context diff --git a/.github/workflows/ui-build-lint-push-containers.yml b/.github/workflows/ui-build-lint-push-containers.yml index 8d14ae0bbe..6de0e6abf3 100644 --- a/.github/workflows/ui-build-lint-push-containers.yml +++ b/.github/workflows/ui-build-lint-push-containers.yml @@ -81,7 +81,7 @@ jobs: - name: Build and push container image (latest) # Comment the following line for testing if: github.event_name == 'push' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.WORKING_DIRECTORY }} build-args: | @@ -96,7 +96,7 @@ jobs: - name: Build and push container image (release) if: github.event_name == 'release' - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.WORKING_DIRECTORY }} build-args: | diff --git a/.github/workflows/ui-pull-request.yml b/.github/workflows/ui-pull-request.yml index 5ee8f2fe6f..942a4efade 100644 --- a/.github/workflows/ui-pull-request.yml +++ b/.github/workflows/ui-pull-request.yml @@ -50,7 +50,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build Container - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 with: context: ${{ env.UI_WORKING_DIR }} # Always build using `prod` target From 887db29d9609ccc0c81c8c205adc139e61fa8484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 5 May 2025 16:38:06 +0200 Subject: [PATCH 252/359] feat(dashboard): support m365 provider (#7633) Co-authored-by: Sergio Garcia --- .../assets/images/providers/m365_provider.png | Bin 0 -> 69594 bytes dashboard/assets/styles/dist/output.css | 5 +- dashboard/compliance/cis_4_0_m365.py | 24 ++++++++++ dashboard/lib/layouts.py | 3 +- dashboard/pages/compliance.py | 11 +++++ dashboard/pages/overview.py | 43 ++++++++++++++++++ docs/img/dashboard.png | Bin 763824 -> 320174 bytes prowler/CHANGELOG.md | 1 + 8 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 dashboard/assets/images/providers/m365_provider.png create mode 100644 dashboard/compliance/cis_4_0_m365.py diff --git a/dashboard/assets/images/providers/m365_provider.png b/dashboard/assets/images/providers/m365_provider.png new file mode 100644 index 0000000000000000000000000000000000000000..d5bc8bbe5f729f80b213974115d9ba84e3b12cdc GIT binary patch literal 69594 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 j=B51qI>6fYnZ 0: filtered_data = data.copy() if azure_clicks % 2 != 0 and "azure" in list(data["PROVIDER"]): @@ -561,6 +573,7 @@ def filter_data( aws_clicks = 0 gcp_clicks = 0 k8s_clicks = 0 + m365_clicks = 0 if gcp_clicks > 0: filtered_data = data.copy() if gcp_clicks % 2 != 0 and "gcp" in list(data["PROVIDER"]): @@ -568,6 +581,7 @@ def filter_data( aws_clicks = 0 azure_clicks = 0 k8s_clicks = 0 + m365_clicks = 0 if k8s_clicks > 0: filtered_data = data.copy() if k8s_clicks % 2 != 0 and "kubernetes" in list(data["PROVIDER"]): @@ -575,6 +589,15 @@ def filter_data( aws_clicks = 0 azure_clicks = 0 gcp_clicks = 0 + m365_clicks = 0 + if m365_clicks > 0: + filtered_data = data.copy() + if m365_clicks % 2 != 0 and "m365" in list(data["PROVIDER"]): + filtered_data = filtered_data[filtered_data["PROVIDER"] == "m365"] + aws_clicks = 0 + azure_clicks = 0 + gcp_clicks = 0 + k8s_clicks = 0 # For all the data, we will add to the status column the value 'MUTED (FAIL)' and 'MUTED (PASS)' depending on the value of the column 'STATUS' and 'MUTED' if "MUTED" in filtered_data.columns: @@ -675,6 +698,8 @@ def filter_data( all_account_names.append(account) if "gcp" in list(data[data["ACCOUNT_NAME"] == account]["PROVIDER"]): all_account_names.append(account) + if "m365" in list(data[data["ACCOUNT_NAME"] == account]["PROVIDER"]): + all_account_names.append(account) all_items = all_account_ids + all_account_names + ["All"] @@ -692,6 +717,8 @@ def filter_data( cloud_accounts_options.append(item + " - AZURE") if "gcp" in list(data[data["ACCOUNT_NAME"] == item]["PROVIDER"]): cloud_accounts_options.append(item + " - GCP") + if "m365" in list(data[data["ACCOUNT_NAME"] == item]["PROVIDER"]): + cloud_accounts_options.append(item + " - M365") # Filter ACCOUNT if cloud_account_values == ["All"]: @@ -790,6 +817,7 @@ def filter_data( service_filter_options = ["All"] all_items = filtered_data["SERVICE_NAME"].unique() + for item in all_items: if item not in service_filter_options and item.__class__.__name__ == "str": if "aws" in list( @@ -808,6 +836,10 @@ def filter_data( filtered_data[filtered_data["SERVICE_NAME"] == item]["PROVIDER"] ): service_filter_options.append(item + " - GCP") + if "m365" in list( + filtered_data[filtered_data["SERVICE_NAME"] == item]["PROVIDER"] + ): + service_filter_options.append(item + " - M365") # Filter Service if service_values == ["All"]: @@ -1235,6 +1267,10 @@ def filter_data( filtered_data.loc[ filtered_data["ACCOUNT_UID"] == account, "ACCOUNT_UID" ] = (account + " - GCP") + if "m365" in list(data[data["ACCOUNT_UID"] == account]["PROVIDER"]): + filtered_data.loc[ + filtered_data["ACCOUNT_UID"] == account, "ACCOUNT_UID" + ] = (account + " - M365") table_collapsible = [] for item in filtered_data.to_dict("records"): @@ -1302,6 +1338,9 @@ def filter_data( k8s_card = create_provider_card( "kubernetes", ks8_provider_logo, "Clusters", full_filtered_data ) + m365_card = create_provider_card( + "m365", m365_provider_logo, "Accounts", full_filtered_data + ) # Subscribe to prowler SaaS card subscribe_card = [ @@ -1346,6 +1385,7 @@ def filter_data( azure_card, gcp_card, k8s_card, + m365_card, subscribe_card, list_files, severity_values, @@ -1360,6 +1400,7 @@ def filter_data( azure_clicks, gcp_clicks, k8s_clicks, + m365_clicks, ) else: return ( @@ -1377,6 +1418,7 @@ def filter_data( azure_card, gcp_card, k8s_card, + m365_card, subscribe_card, list_files, severity_values, @@ -1391,6 +1433,7 @@ def filter_data( azure_clicks, gcp_clicks, k8s_clicks, + m365_clicks, ) diff --git a/docs/img/dashboard.png b/docs/img/dashboard.png index 2d2fe3cc9554a5b9663156494d882f232a28b205..2392debbb7c70c6c15388994bfbb173c2fd01586 100644 GIT binary patch literal 320174 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 z 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

    C2BMMM)}-}~-`UvpN#kqA4ii#RM}zI3X>#jF&) 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%0ADi$+eTo!}klDC}9l5dD+8bgV?=Y@JVO5_B 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

    b3H@{ucJzbWe-J}0r_ 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

    XGjJ7Cn8)F0gyCOR037OeMEyxDa9GBNw1) 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 Qb*QhD4#~`$FBl@^l2CObNmycK7HWoiJo&bZypW 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

    LLBBp7m+ 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

    ivTBSxh7>N0R4EL44Ak?BVQJY#otbCE8!% zpXPcz@Fudzq=>it_~*`~!>|5IZ9ZUBA4>Qo&CM@14Tkd7%}9e<-$;=#(h-hW#1b73O0vQ-Y(tNHYktx}sVi75 zw~Nd>{&m9co#BHzaCxQwxI93A{5Ju&4LY*`eO~%{L$T*ihQ({qTMWvhmsf>BuKqfR>`u6w;wHz!Yvz^JdPz}Ak zMS}EHL5k)ak{lF-cAE?WU^*>x^UxT-%M*5W!}ZWxY9z^e~6YPEOC*QG_YDozU6acxGZ&-4~KDWnPr{)i}P=irZ$>dNsyJu!q*0W+q zIJD~rmec`5JVgj?pMD(*4{nd$a@lFC4#oV%jWJR-R*#<5rQw80=57#CFo`LROwh~Y z3a_NeU2lb9230f&ie1FP6ih zF|1n&E=-B4MZ%dzbEhjt$gVoFp<7WpJB(b^kC{scRg`d6@PeU5U8N#M#tzULZ?HQ7 zYfcBnzyRxTfZQ7W;_#a!^Qev#18W}d$=TEwV5DFC*K68)PpI4^LGc(6{f_r9co7UG z0Z61hwgCxo8yo~Af|13+lREe$DsKDdlYV)5j$u225fS2>L&K}53Yj+dX`WzfOy%>% zx?_x^_eshM;naj6iWjPube5$bhOFkQN_y zzhhB#IHgcE4=4{7Hc;PNYXjW?42~0pZwuKr=+%hSICjNVV9G@KZ@t>S4c_9?S5%4gui=6~Im}b3qGcE$LX)t7@Ngp4V zZZ#E~!Q#j12Yr!S+YBXNo?qy?#*!pf6&$p|)u{w`C+}pdmBv_rd|Ub((7X7~fs&!CH`@9nKHph>LE-(c)aIk} zb3bl4z3}c0X=t^dxp>Q9G8Gtx!omi2buHQT9~QytEjFK#ATBm+e{q<59i&WZwBU;E z;d0tw#7VFJ6lS*cA>2|`2`*nF=rSQAY$QvMuDDK$ANkFn#Qdkp$p1|yKlH2n)L0pC z#A`0~Owr;+!lXvC%m%=ajCDdcp6~uJeetWwS=}c!4ujM+D}YN{>~)TAYS87HbCeL_ zG-$^~ZFSy7I!Z$~3D=ZvPyx<{kU0^WohZ2L${5KOCX= zpa>Ua6JbEdpp%2E7`mv;wQ;c8v~uUq0tXA}c$VowQX|#Oze%~V!L}TrQv}d^L#&Jf z%FozxHtCYsJAhVCG_JZeDd%|l)zWKi8tzH!`3ktw)(d_nnd_8F>CK^{`6e?AEwCtb zeITxn~Pb9q^0b}=2CoXzP1#Y_@8TB)M>U^YV+vTuLC{n@DxMWQ87^O zwJLL{@UeD^vbFf+yxI06nSeO{onc>6_|t|dvpv8g;Ga45mC{6r9WNXvClU_ zLVJQu<)z)audrD*#yHPZ2m<5fS>-TYLcV({Jro|h@l)elM(sxCigbBRa;Ezs4LzzJ1y!ED}UxrbwA(?O=48Q|BMGNIijy| zfYoYB-YPgr+3|2bpqT&8_t&Dk_}TZwQ_`LBQU=i1G|g`ZFo#4n{>{n1VY75tZX#Hxyd5LmU6k~O^bEZ0{rRt&?D>TJ)aHq$&M#k zvgTTI?Y}kZq4}P@1jFhq4~%mjM~e!hvc`)#zZ`{!kiR1TD2m02-a^!eXts0CBOpg4 z@}`9p3&;sjfJ~##OF)Grh0tWUdrLt#_^lCBIBmZIiUka#`W$JYdLJM^TVHbtq=E&M|YLxx74$r{g0gY;N zgM&|S2?;?Ss_TcDsC;c86R*&kwf`|n|4#jiLiYyJ$LP7h!}Q&vv^89ufG!ot=|DE> zy!)NqcmKyb!mo>7&>1Py5h}w~ZGNYlT?a-za;dMG?Zn;#!BO-5&a?OP4dXeJ!Rkb8 z$%f=mg({^lgid@B#N=W>!j7Y7qB-99BUd&|i_CbJoINx@diZ!X*TfjdjP9LQvfsrp z>1aW*wn7}S5>qkHy2^mh3hBxKdV&AmmGK)x6;2pezlCB08w#q-=QWTIA!FC(m0b1f z?0eHD-{z^I1tB1CIJ`PPWxA@Id22C|0RZ3*>j#6JGseR5QQ_h>;hKD%O#jRG`ye!B zlmebwt40l)lk>qH72=Eq^YNX5MD6G*`_>FzI zW40eyF%u_tkKW9&(zcchk?XJ=q4DSvtqO;}eI#c|M!xdxQ-VZG)b+zm`}fGX-uYk8 zoi(TCXO%j7!*w-EzwLDnTJS^wfaWUu519w)8Hje=I@_63n1Pn&0>x+B=wS)THWiSd zPQM9u1eM_-lE@edNr%jhXZuGmOYTJ_}beEY{(U; zlLaMabr^4!^rki4Xo7)fW4W*a0Rc(HX09ZM&vJQWocAt|ol9gi9XMzf4KqQ9SB7A7 z14OmXp4Ho4!oc?+t(68^)mJ_5gXmMZgUautFL&Mh*b0R&_{Cg5D5eYfl^aabkB_OB zb1FeifC`2!hODdZ+gyB8s%o;F$Qly=Gk((VntTDRL-%1M5wZTB0$->1x{$C%&Lg3| zv>Y=;CckHkRieB~HS>d!N!%Da(V7&1ZQ*0Za3T;hr&wX{M-^EXKqO`T%;>|p^OuKE z``_^p<1*JYU9h;o;hg8(l9$FRSx@ZVD z=#skbE0U#h=DTjJ6M8M__$+-c{W_C7=|5p1U+Ti7p#{37U#R{qE`@kK^G1MFXpf>I zjA&GZT1JQpJCxw`a@ZAn?|<#g<8|;8M7^cL>H$?LNIO;_9^L4nPRu=w>YDXUjpgNH zD{s(Jc9h6nueNBf*BPrdI($Yvt zqjYzJbT^1Jh_p0F2uMkHm$V=q(%qfkb*sU5vnO7Vc;r-WCrsLiU> zux zH*E)_A1%Cj-&)imIH%%v1aQ90!-eXg=FxRt**`|BXXnK93veh-rrwP%c4rgJNO(N}VzG5Mf%E$p_5 z#|^_}Pj=p2w)snk(*}2!7uFJpLUbQh1}q;M~>Bni9|8xj&G5=GCKr=-J(`xz~ z>{Qs=ch=iLbg_cGj8XdX41RZ*w3!;b{Je~&yG5c>BhdF=J{bUtfBN<9gJdDuo~h?w z_}<^SFH?DWdv_%P;%1`Hc}@{hjjT{vk#YRYLiqUE5f3mm3S|=Qpc1dKwK{L798!$4O{{mEtgn z5!U}#j1Znd`)hK;;2{C#iT~GJXloywHRhJO=GZ4F*=AGWmgcD%*V0;T+?P#4PDvQp zPw3R4j_bjy%CN5RA1-Fs>$6|X7qWwL*9NXD7@!z*8+jnr=C?Y=H2%qI;{F6ChWD~p zIG(GRr+bs=^nLWTz%=^pLT%^{cS-nsy)k*5L$5-gPMP`h)w2r6r2RLXyB+AcoHu5? zkzafd8gG~pnhp)~s`Frz*I1rCdsJ1J@1stGQn#8SUQC?V(A4*0{~_aWSanghOSxY& zk2{Obo0futZ0~bXYIcw^190W&URh&U@~67xbzg?-_PTpQK}i`DIpBNp(`H-VU?^g6 zd?TNbOKhz_UZsVR(->1HHgAya@mJkCtd951EZ35e_m7Bqo%{7yUIkM_PpKW$v=8UM z#5iF+L)NGs(yK5hS4KIO{6h2q)7Mw6n_$y0H({BnKKXXKIUVn#unSVBw894>;^(MG zeMi%Eb9<9cEE6OuFTdA$>oC89`T1AV@^jPDF%^c@W<63j_BRW=`WP}9#XcusqaqH4 zi-i>+r{(j~>m`iC+M|JEk=Kg~cet@M^6$I`{W~Pt-ck8V=^P!6KLm5!JuUo;>n@9J zDo(GguUA^{?>1)}5;yOiC*R^QD!-}(vbqc(RDpDe#&XQar3xE+N0F~?tSBECD4D8i z*_WeL#j^-_0H9<9+?8TgcUTGflI-2lfE~c2O~J#iCBr++C7W4TTLE$<Y%5P2mxn=X)6 zE|EcNiSuqH_Q?txTe@D2Q9GGW;#M4X&m75qPXJ3yaI8!X`5S;)08L^q&yZ2^Y+lY4X}A#>+WNtsEHtE;R5 z&yFRA`LfPHIG~5B(UL5`f3v;#+_lu^z$5o0t{o*eqvnEbCf4u!U#^N-K_Q9}NZ+IM zH?sez1qrEvT9ES-4{gI&q}DNo9Wb?>CzrCkMqZi?NFLJ;N}(&ba9rkICt8;2T8E(H z52VItKW7h?0D{1pWXPy;0mhbkQ6x58`Cf+gj#FVOMH9}DXT<=M*yVR6YygT~fSX18 z#=aDRN|;8~$N*Hr{|i)qRNXl=9w4x8x{H;*Jz9EXPOzXXaB(Uzwnr4A%Zg2ZWM5d+ z9IYa3=eZ()q*laPKofnB^E^(K{}Xu{LG<&u&X#8P`YJN1Dpcao58dYAoGXeCfB1ey+}Xg#eN|1uXx7Oip9 zU_qFXTgP}Nm&8E;44H97HFQ`O?Jz&`aZ5{Q=c|6z%=vLLObObZ33-(br3%9&JZ`Mc zM4nglEz~mc6+FRTe5arIC9e-Ff1pAcHirJhBnj3?D??8Xx9p1nvj}TkzrK@{{dd$E z!^wQ;per7qLJ$R#>Qa;ILN{=GWRK`0cHk%V=BEfu>Q648W&qWGIVBhftV(YA>k<~y z?6B5vFnEn>x-!JmCkvIp-Kmf!NUer6B*++!+T*ZtyjPjFs~jjx*xcM)@Fp9-kVcG> z<5+@5b$SQQb`A$#tGa)ot1%2NRapPDZ>tv1br_kw&L=D@KA3Erd+H3u9v-VK@K4*+ z6ww?t8Q9Tg8IP*`RxbEIr3H_TBR@RJFJV&{R;3M}RBqC$o$=QVxTwejsvu z34GwRRQ?Kcbu!~~hp4}aNE)J>Tk4u2czKu;{X;Jx9FOJYJ-_Nd4mc)d28h2q6Tf5G zACWis30R>xb`-l8*I~SSL~DrIcKU*6bFoCBqobE*$6{3T3O7S9ASQ!X%ij+_?pG~| z{AOW6e8?n*`NHSt`~gm17d#C!Qcne_p?dt)dvzvp_&lcN}97Eb8%1~U#LC0=+vNOTq1V3Z$ zAE;>5UO#QTr{f|$5((JTWR0U&#h(bcJ?yOtKa?-Gl`KE?aYIDN-YxrenBZc+A_DV5 zd}%2STiw3xDqB{q^GAg_HV3o%k0(lw@>soGpp{Y)DPMyJ&S!R3&^o zKgSU%CI5`Z@0zCEYdqW8fPWC1)Hc@<7|5epZk#V(!0UgKB}$|DebK$-0Aa6TxS=vN7*4Z2eqeRJDET`S-F`DHcn61q$0+<4 zxQ1h@lqix&NlCd~G+jKmJJdIzJlLl`IG(6GIl1&2FL*qe#%~Xk##@PZ2XT(Ndh|qW z7H|p#xT6Na5DY*}qb5oYVrLv7nF7A$^5%Q0$hGG$78kInDi*ht>$+tav zqxs4+OeZz%D|P(^8zi$INS3gwEHOXc-!lw~Z;{v5d7`~{t+glp@U;sl`pL9B$ib{w zy3}6)V2{*Gr03@DP7dLl28n^cr5EtGtcF~^>YGYR$YtMQ^W1M_Y>w5%B5`mqKA!ct zhbJc|zed;I!0hhs&OT!w7WVo0&1>LKY;%?xH-#x<_BYp|ES=w>T7T5hSI|?oZwIw6 zMm_7)l##(wnBaz^vV1_Puqu~Q5){aO+D%Q}UjPB~`2_G(B9j*w&VS4tKZP1!l4G>4N_0G7+-w-q%gI5S4 z_F>&v60U#ES>hn(EU#}rso&n;-4rN&dw=NMnV*sE8J(VecQ^heiNikN^7ar|Oc5By z1nE^k$qF`;@Zs9b=7!Z@pYHkxBBBF}LfoX=z46DBd$SFAu-9i#?i$W_gN`4dqZ$u} z%RRt-X8l6=Sjy_R zPnu6H8zTKHtja*Im#hWmdar79J^AmFGHS?v9qLXDk6vmasPeiV&GZ zN!d97&fMf*&t&^k`PxRlZtD_#ug5rE}Wm>3xPAya4g z#)gIz2&a3LZwq5qc4kY3-g{qWeSgXM#82gR8Fk!B6M2HgMzpHMwL{C}I8G<{lqwvt zPI{@vH+(s9Mfa6__1<+wG>*uGFe$&sot~S92K!%=DxJ5ZNx(u|e@yShj)_L4c&p#} zXdYt=K9sqf{X9P%p zTH{0znJ>5S&r2-O{}AgyI1|Uok?;*dOM62~R^_oK{g~*wd2{h>mSmMhv6XS`uRT=u zL67^%#Dgsa+LsyJ@fxt`CEj1|&(bIHTYTJ%;&CQi7#p-Y{spEop8F5^{;rPPvjzBp zqB@wi7izy80ri71>bqXvap8|n`xI7+8^}LjxoH-4cwe9!J~S<=)K`h_WWG)Rv|X3a zwS3PX5v=v|Qyt!=H7%U7*I4mz2(4z32<3V&(sLk-Fw^+kUSNcw9}|cM-32EMR~ZSh zr`)Qi5ec9!dIs`FF-0~|g@JPp^SfPt-TYj%*+5H>kjwJj7P~27n16bJ_r+dKxsT2^ zqL0b}D-{@W@cPldM}#C+lj_B5@U}Q1%|Xu+eIz1%UD~<(s?(ZqB$Z$s zei=GwSl_Zg_SKW~-cDdkm_BICa##GO$kV^r4AW8@OfdLa$Gjhv6x#ODQ}zl2g(yrO zY-h}GL(F~UXEr*uc8Ug#uS=r8u2=qGh1Pg=E7tYM67Co^4gMIf6TA?kRg=i7x~QlMn4PybJ5(w2pA$M|Iud5Nw|@ryZHyz9WXs8k{vOLT|pZNM!- ztk+zVBjVZiXThhdKVmYntSjVhkIHL*enq4KTxGL^b(G{2XJDM>?l%(j+Li? za8Iiynq~0?P3g0Di>YpMc+zJ&ktq~Gw=8pCxNA5Mj-z)c8yMdV1@(^==lnb(F{d)i zC2#haH!76__YK>f=fJq2d0O4y`dJ;~T}%9c?MDnIXwT~Dz6^StWVLDKTBaP-3!?YYE!XVhmaB!)Aj zfa72jZHg`wc#?%S>_lJjyO!!?Z?fc39wP-WJCUaiI#@(#H{`rS*CqP*V}s%oRC?(V zb>VZawnfSO`@_&;=lykqi~CLor6g6B1qv)#^0vi4C<=1J zT8wLkULD{j0#nrQxPzlPW(ueKvkFKR0Gmv&u_PxlX#~V%_)sjgd~YwUBI0^Uq7;RP zfZ7RmGj!gZbM8#$$R;b>Pl;?jz+b<5P#`0nZ@6d$+r;8!I<>2;lqF?lBh+PlSl=Bd zPyFp;wV$Wh=4ZQy<8C|SaDAa;^ZMWR*v8bi}H;WdE%DdZWsW9wnSJHA+i@ELPN(=V_p_1qf63QQ=LVlySofaiKXRfg zbEZTr%*r7$wdS|7Os#T0tK_&l0tb|5By9;KWPSK~Uf>#1w0hK2QO$}c%P=nsR(~qpA^al21 zaWb6;PrfG@Tn3XCcpo$CPnPH?ZAd)`BTbJ$+DI?|zuQO&+jf1CDqu!RJa_i1of^(D z`-6`(@u{DLgA)$PKnjAGfMU}T^D&ZxD=FE-aKnt*>H7rBk$6LVcO{@H6|AU1c z94g$9Qq(rk9`>Mc!GLc>tPiB@gScsM$phoaKez%o2eigkMNWsld4`l2FbnPY7WqZ=2y z*>pe6Y)_x5!ofp}i(`tsh9h^vQ1n2hA{SU3=uAExXmXuNPUgI)GBZ7&HamD&xNs+B zXE59506sk`b-oWx7y6^^L0xbr+pAL8fD=sAeIq|Eze*5KWr$IgKltE?%?m- zoQr*cM!D#Ti=^(ZsOxy&_tzDOP1-satKEW53SS!u={-k^;+@rW-)?nuBugH(-A@zF z5w2OTy#EAS={Sl|r;*I_!V$&+opk&qigHPqbl_X){=~@=d#Ku6L=6U8Y<<%0Ni~zt zw!rBAkkr4Cxb^b|88$uCiQZZAbL34(H$tp|KJy_I_Ey$XB(cV-fLu@ znR47}*W!@W^{jgnBPf+Ir4f$@2dAm)Cx$=R1H;LoK6n4@DZD!?-;72wj<3j?ny*3a z(fIlaej`?uY6;4J_`)k#5B+YxwZDyp02?zfe`XG4%c!R#A8vJV+t(%KTO2X;>f+Et zpP3^E)4y2s}byAV`ori1!!WnUpxCsw-k^Qnn^v7l5;UL7r0m0 zS&JHGpN5lJW@((P(>=R=lZFpgx?CR~E1Z3kmDeq)xU4Hj?<$R%q%=nNXlmc@jrQJ* z;&p!^eV&Sjb;4J@xGb8NQo|TbV&oiDea@?5m ztX(u*;g=H6H1}@c)2e+!Yfqi-gpE7H?i8E(h)b9PGUtTN4q zr%DP2=ZN2==lf);E#|Z9C`gFzS_5mZerm1B)UGavL&m#8&Sg+uzXnfaDi~yaB_bpZ$(KV|8Eiv|mtTIpr5eJ1~-#QuXqE2=;eDU+lwb*tcbX>tFnMPMGb z!~zqBWG&p{^ARTkhSfJdefp!Y9cZ(mL}7pZ6F$JtQ)Jou9Y<@q8P$O@FHLujDP7cf zZgC1%Q8tHd)y}qa&O^0CxJ(1(=Qm?4aEkQos7&V%Va!?^Z-QPC&iH;|=;as9f` zy@)2PHukV+&66I7|HA+Q5{L{A28SyiRmR)keQN)DXTwh{eNxTui3?}QWr$}4qwO9r zyP#+77*qkie_!utILELPB`x7SLR6)?D~7hv`vO}}<1{`bPWZW0BdC%ZfnxWbftQ`eUmvs=a2e@m{;1kPY}>@d|F)0% z*<@#TgxaQCWkp|Qd>S`;N^I-Gf_PX=y5ZB*=odEmbnM^|uRFg5hk~Sd|8+zk$;3fN z#jSCA9nWd9>*Z(+tx!I&@gQ6x3hVN2O2Vt&syXNRCeuQ#q3GP$Dz5zl z$0TfU(fsGNmW6k7RaS`<{IM)R<_KIgz^(L)hYCvk_qlr2x&}vQ{j9-n8-;yUnTvLz zDgo+dM6>y{M8Qv>U^oQ#Cy4x-!$}Nra()8pT%-$C!G4?GbWIh0Ql9zboO~M4SRY&_ zYwPxr;-VRC(K9hr`{tVAzc`w~);Wy3OUhn^D`q*OpT!Bukdb+yCt$F#xPO4UQEVxA zM(GXNp5Ti_*We5P*_IXu#Gp+OgIE-qlh2?fsZ1Ve^Wl%%HW`qbiK-YRlxvV zYIPApp>33i{&#xgiIAR!sEP6-8F8_nk9}Orc%&Zx+-51cz9>s1oJGhw~c zo+e|2SvP+Wy6ND{ubNfmPSX{J7i%bAwKybQT)6H}Mji}03topsHZ~+SexLM%p48v1 zweMQDnJa_7yE#)S@fAEkk#jR$h40zznEmj=U97yyt!*C87+QUR)0RvztD*th;PfA? z01F91&}@mUL69Jn2S-+m4GBU4c>OEC%FzXM_3=LUkT{9Ncwtc7j3A2R@{6BmF2Ns5 zxn*DcI|EQeV(1r^Dkx52(j=Y;MZ8Z!*HoItZrJo_>9f-c!_Q$XEe zym6ZoyfSxTg%PI^Q~Y~M417ChA@TdPTA!we3bStTe=-5oUa>5HqZH%_sn2fFhU-~tqE~45DlW0iYGEwIy%KhU`R2;fnIYMA z|8V5WK^*bJ&?-FY<59A({z1Axt&6blQvna<=_{-D&tS5$Wi@xfbA!0?ex?X0%XxKR&46I(}3lC8&H}3F-YNaJp z`0l`UsLU`)z}_E*RUs}$3cTRp11!bSr)^*cO&(*j9ycu>E;HL@Lh38{u4B89T~Tzr zN$M}6P?gn;wN4{mNiH083SvD|lK=+EhnLt2*}8YvdCWY& z?k=8NjESYX%vfBmetSWFqkDIAP`h$I8|SXaq#04DQuKaTG##SDonv#Ldh3&ILW2zy(7TWHnLl`V9Ea_C&)n3dww>#(Fp}w|`X#TKp z=H^;4K3$IJ*2=V#vaL(plc&<@kZQrqmUDatD|oY|A|@RpyoFD-D_#C5r10sSo~0^) ze`X{a!6mcnzfMV%FhWXL@i2QBatxAs}=x@C~iJC+zLqB6EWE-mij_H@t!V75nVxF%}Jf6?kzmRTgoxV`qCj@OD`+hU?y~HHU@bO5tClPW1Gjq<$*4@Bz zri4iSvTd4yrRg1TM`d_OyWflE42gS=KR@9eYe_H??`uu?zb4dwPn&cUy zCbLA}Mv#Y9zyxJzqSC)*C_i*koa?g3KGb^4F}o2KT?(j6O-_F4K%UpKuvVrV3B&1V zp=bLUKBkN%P4^x)^cr0(i)yYj9xih{r=)g~E<$l_7+df=0fr3DZ_8lHjt-iF)gCUw zc)yMe+rjBa3mqc~-krw2^a01t6bEOPbI_tto_06dWA1uBJ=6HNpp@d6B#zCK9WD7D zi1_)1o|Gft{EtppTIjONUn1~7Pitk7oHW|s56Zhi?J`g{#o68~j3S(6Amd{|klgMu zk~G`m*5~Y>RaqZRQZ0BI^0;Wc@Mmqm^Hd>0&K zGq(M(0G={}+6AfKM!K)=w|LiWLbtuDAea4tfdR3xqm{78+r=$+y&=hYkF&}b$4lQ7 z1lx?F1+#TxgY<7M4km9a1$P*|E{|w~T%b7rAbHFGjO3kc385($Z{$#3>Ptc*JRI{! z^p{4Y*O|Qm`Mo4KjlzP+0EWlDL`kLbR9srVq~myfb9fQ!Yj|~JqDehe;>7Gh<@9qX zjpXy!Yl1ByFCDswsUll3r`Wupk|VJUzXE{*(icpPVt(EQdUEkG&5-SIdT?<%tq7+( zi46H^Nx;CYrGMC3N;m_Y?{$RvZ^eQsHjmFPe!bInL9LC~_12~3=(3> z)R>QAIj#>fm|_nEsp+|EVEKI=lYP)`P@UGHREM4d8)lw+&nVk8H>M;pHhzp&gx6Q1 zk!ufUS#84i8RVQa+(MVJzZ@Ztqk&?e6TG>L=A1zzJD!0pZNRmfEEegIh%DROv0atv zKbnjpuDuUhb_kY4=m2N!i_dltSicTwODq7(8W zf!Rl3D=_9Tc66FyOQCixIc}sLYc*PINcpTD zLfW^b(Mk&?*;IabPRpN+ZW=_sfB3FSn(H^V+CE)R-0r&)sq9_TYt@?G{^8le{xi>( z>w1C&SQT4coMn$ULf==Z-bUVH5ZsKQtKjlUo@Y*-9mzQDinb_g&hbwNF8}OShzXqv zK92oKe`8AVf<=8pj*l&p!7eS?c|1i$rUDPE1abv~8Fe<%ogd zsj9jZ5FnrT7s!*sym;{<1dN3WWBS1Z!M(5aFo@u8AcDgWhb2HteSKVi_>-2-z#K`2 zeFSuZ07(+hMzKi&&(l_a*qeCImQs!IDfJcKqwyRqHF2jW#ZblO`VSWwh(}#5hLwt7 z){R*spkcpO$9}Te+fz2>1zAwmpSq z4y%R6q(d2J!~g!-_~!0)Ck8i<_m9w3BbOAqd~w-dC9`_a{XCHV*x1a%K&;9#xc2+C z#m3Wj62hG%kC|XKJ^djtGwd(Se1M2XT0VgYiu6f%6mL5){nc-Sb~67mWLcmlhltDB z9wNCHUzW-oyA(g$J`_Ud_q)>b$@T>m?%FR@;_41P$Z! z!J0*Kj1SeVYX&d;m8LD+JmympN{x*D0Z$z6fcacP+m0ETM_OO9Unr@}xjN^0T$NkZ z@x-D238qQ%Aqld&bZajPm?hNEBm*%e|dvWlQg|ox_jLF2ZtT3mqlNWbC+-~9DzPU^FBHxJOY(}04iZ&@LM47jm1q8=7xUpkdfvI0sqC&`qn@=! z_5-)BC+b1-Nwvd)Z)sE1cjlHxu?9uv!fXaUIQ=j5^qY=XCR3o811jdDzSI}yqZC4F zoC#xa`oQX|%YDB78DDUf%_N#qo}46D4*|A~et_X|jg!hZkpTUd756C+TB@@Eu#beku%UTv2QI9_-HpB{jdcP}h)$kGC zaOJiA$RLukv>g={3)3@AbdOLbN91%6QZnNI274iJ09U2!14(cJkVVZS1?InnZAq7Q?>T6 zpSW$KhFdPNj%{D!kCd`-+011F`mH^?Wn7VUD{THp;Y+xPMqsI`emN(e4sb~C zguSixF+#_fX(#`06ygYJe>hT~S-%7z$rD%FzY_wIp7^zA?Ewm-nsOsR9H|U39O~B> zO7I<`D~1Q(QCgQqp2JX_8PKpjKgyu*9T-%0>lEu;TKAyDpubyLjj6C>uE3f!C-3F+ z>6&N7is7`f0D&mO@09?)4{qv~3j`)T`iHY3|G*&dA>je_@g^pF1=*?p zFS^#x9d5tw1kLMYkUOk{Wu2upSuQ1E^LCGWu@mf#%9``sidP%i=r5A4L|MyzR$rkB zb>3LXK3VxiDQ@Kc=8zJf*UPP(bwa%#Jm#^cVErmLHJVgUG=rd_p`o39sjeF^0O{=N zTInJ6Y5mF_{bnER??Tz*bLxa_dhQ`{7pvnk-ejHQaAUn+XhOM|bH;n4q(mOx)2wq1 z3v;ZM%KsSia`m9J{QA|s?RU1-fq*_(q6_iacOQj}a2X{Nsq_h;M}@2c8Na?<00Dm0Os;T`=cQ*EWT z%*zttiKdjl8d{JipW!c`#+Uf-TVmZS$87-6DP-|=OwMtqhWJXH@0?)G zYiQ2he6%9hB|7jBsj=z|c2{Z|d%>8|MO$W@%yMx5e>6T0|{k-6W?nxm`oC-jLoB2C*lkSQV0t zxwgB$N4MiYNkXtuPa_|@fqhct*nmio!o4(}NQ$RfecPp$sm&*7#st^36#7cQob`#k z>vKrTK2rXNNK^!Kpq;;Uw+M9%MeY`nW@6iU|sZbBWYDWJMI>AV zChKn)*F6=^n*zi7nqg(37LZ}Kd-yMaFjx>Igh}AM^c-@BStJmCN@PJOTg{QCXG%b_sC;w_E{3T=A=4&0zN`|NmU zxT(OO<+&S6$Ytn(X5undAR~PJC0&|@iII!GL45zHLH;fmezC?>kAqQ7kFUn@gZC}| z8&f%9P@CFJ_x?zsxZfs%vPeWHS;xZ2MI0OqTbPr8!0G3I;j}Lt09+52LlIJB=8)1T z^3Q5teL`rBOQ*grJo@_~!HuV0hrcAdyz=w%mgih-;&&#j##<}agz&y0Zv^PTl<6BP z8A%mr696Lg$w1sot_<&EWD?I)%(a<-pl~~nSelu;>aSYlpdadebJlUfvW^nxvNsbX zq+Qx%fg)^93Mz^#??#LtIm~Y!dH}=2fK~~L#@a%g2p?X*gozjy*cKoKfSZg6 z9ZK^O19T+xLf{zDUP5ZouFS1wS(x1pwxh#5RB)5Igx9g^!A-9ZG1muyAQP~ef^;wx zr@xT5bl!it$+I}35mRd$nc=qFa6xnU@x#uc+ijIZsE~=MKo|Q7;yhraDqSLBPmn@J z0@qDM72f`CRj2;js=fk-6z;SodIzPu$&mGh%pj^e{oMk|NIueHt7kn|D{>_8w{S=K zdh)l1>96uUXwaK^vJ>_4qQ-h5B8Kw4)ufO5IW`3aMdisDLg8ki*}AGj|k~w!Ef$tf5bfvIp`KP)EQ(wY#{|WD`E4SjOK*<)OV(%)8<5$<<6Oj)0D$^Rk z0$tD!eezp0uxxCgLj{TG#YVEj*N~VHVQ#<#?tYcmmH-bpoh6>peqKoMnHqCEgcIBB zAdM<*orx`~${a2l!`_2bpw*}q-(qf$oQw~q<6Dfq#Fd|VF;FZopOo4gKZC~f7#V-J zIS>!|)h7Rj8!(IQJCOq90=*Eq0099lq4<~q|Jkzut(>PxQSuF(Y+_HfC$17fY z7%+Lz%4ge>`}O2USbTx%*H13Y=&HB3>=KWO3U#zv?6CnDsB&~Z9A5NYS?!D6rU!Bu z%+AN^Ux6)x=!^bc?6y|CNT^0T>Wz=)WBt70nrAMs6NuFfAnXK3^&V`< zNY)Kr0!@4ctf{e%Me#B9x5?Z|w(2 zghC8&&21Aj#^wRd?M)~6+Gbfl?_NQ>ParL9J+kvo_WR+T6lpCx#ZEx*f5IK9X1u+1n91G1c#$limAnw-xC>1UB)82EJK?bFaASb^RAR zBR#II*DFcoas{fXBZz7WplR7?j01>j%8wJSB6solWNGuJ-27KN8=l)A{#NdJiaxx) z=-YbaBGo%hYoAe+L~RFpUC)!j?8N8yO&5p2ritFAX*1~Z(ydtYPIC0SNqR5?6rb}p zPQB|^#Q3iUmmN6%Rg zu>K_Fg+C^4D3h8Q7sP)~H18I$( z(I~qydYCS`Z)cC-sbre?&_@9}2j^Stlpo%;%#&8p#d2Q9dD)j;003KaK@oa|3HdE_@1R})ChAHcmOTol^ z?KK$>4j@t2g+SN)4t21F7YX8n^||VJQf0d`(?{3s-W{Omj0zMrI>&sur7ggq4+zdyo68c${M5ECG`w}?BK+rZj zXT>NoL<8N1WG%N4**7bQ#aMW2_g3J9h9j&f#n+z_IClNP!r#8U;$nep3vTr;dkQX% zj!lUQniP9U)P)pp(c}ves4pv&J07Wl^q{1E$;ohK)WjphMkWFEsfQ z*QW}&BmzxQl@JnoNfL09A)c)I>)K;P6>a6t)-JPwI-c1PJSWZCWFw zKrR7yX)yTjR1vsW(zL7wJ^54i%cWzePaA)bHABA@TJb=nTpFX&7lhurs9zf8WT6DS zdZ&?a2g69Sv<#-Gkt_-AAKI{S`YDc|`?nH#Q*r2|*wZ>L5M3r9klnKV)D{;)mJEi8 z7z;ttl~~Eg3nL>^kCyIiGtlQ~dU+oL`W(@`;i=S~imTg~v|O||huQ7avb5T|>h$=&l#Q3QUBRpwGC*oIve+4`Mw)qu*u3Ylj*@TaN7!Q0>5c*4KW z$A6?tAYf4OU2BS#nSpKp0)<)^kBv$$JOXFs1-E->%!`~uUjGeldEqzL_T)brvlqlS zbyuE}8yP7s(EM|;ME|{u&A(=)=6e!*AwS`hZ0e;9^L~;5Zq``s(Lobv|`#NWpvF90yR5q2;{2z3%PtTdj|*O!Lr^-g{!lr&`>afthZ)X z4b+q%F#*`|TU!8W;L#TKW=5z36mlIr)j$&SX9vO|orGs?`go)F$~o>=#3y zeddCB;wCHC=Ry`9RM5nKibPq&5*b@SRF1VHKjnhghrtWZ0s=LB8h|q2V~+XD!9{o- z)X5DbEa-Fc*;WfslH@bAo|(YNpZ%)%tasQG zx>!l!R5S;>p=zCzrp4Pk)ZT}lPhqwwG{fdEjT}Pi#6V$aRAu#aO0@M0NhK{`$ucg4 zmy!PRw|!0VfflOaS`T{4;}L*BJ^%t;gWBZBA4A;VO?Ll}$c>E_Y*C+y>96uS)L3FV z^#rIf@zJpk3H@EG2fG*huF%oM`b!-n&o{LWU}9bxG76IabJ$e>y~C!xW<`8~-(rTv z=D>zC5);zSlpiTvc^XYD+20ubp~^X@TA3^_mFm8p07x~gCV9%D{jdeh^<1?3m>^YH z{F}d^Pm+uk9P5Kh8bPe^2S^=;g)<0=cfUVjm~K8RZdAFnPa2rpg9Oh!v$W1!DBiW> zziL&6!FKfu+oQc_o5y=u-Z^XlfOF^U{k%%WQrle^sluFCcCbb01x;s z^^zF+ObWT0BP`?rkN=lb=X7jE%&g^~e-5%=^$fP7m5Z5G_8w3`2FC2?q3 zUG5rQ^+_}Pi25k_5d#;U?Gm_Wkw=Y2%;AA}G8 zhVjGHd1F98rWCG4sRO@G$uxXwusX;M#4-W?x2YyVkXW`C{qz3G1mGX1htnC>fmm_< z+fpw9c&^QA9VgnsNd>td4)}oYH_47&%W$ci9U6#&Z7~snnyjMRk6*48!0pWyid?@J ziaDQ1eYyW#Z-I18vzi_>`OdNIvJv+NKNQvdZY4?o53#iem4HI^1~inmK|^VT9Ap|a zvV}jxzmT^&zBS3&mV$}z>-dfQLT&YEJWsxZBdzGt43$2zKe{VR`%KObfAIXGm)S8i>l;38A}9qX__dY9>J59h+tN1s7Tk%^aX-52El;EqJP_n;o0 z|Mu#Kom^xQh~fyzz6WCcv_CLExNIv%Z_00wSN8;M)BEy@weFKR(aAA0@IX%8|9?(> zaPZC*v8?D}9@<&}RIv(I$@Iu@kZpJX-~3)d4teS`dHj1Oo8K4D4J>oR)jEi-_?XAq z(S3mzrdATlF}TCYjoJEsR`0_t?-^{MDxd5v$4AA5vmU>Y{nS!7pFy zmZmu_J%w)Y9I2D7tLTNi=M%607rBGFNsHVH1D4)_Tvl{FkN_7z2B?3G59WWQnHYOuDc{=PsDsb|#kdsG_`e6;yyJyQ@8*f?WZ|Jh*C>06%5u$DW zqM)ur^WUfl0=*-YUrV8|knh49AG?sIrh_e}Et1My*&K3xS1GyJNGNyE;`I`%cYCGe z;yd;J4{L83R)yER3&R$qluk+M6cnUWxp;r6i=KB{x#iA>G~G&AT=~ zeg5a1=XuZdd^p#&zxYAjd#yDy_uMmc&o0%eSX8BiSjt5%w>2RqQI^gkln3H?l4hrA zYdiqX^_c1Fzgp2?UJeiD5KQ>U@PHehiWRKASm{{-g~TKWhi6PcGW=^_1#oKxu-K)BlkHV@ zSG!kxKzRv^UDUR*b>zgC{g==21w>EM*62t6QA{VzTw3p1D^HtH4XRz1p z@UPbmcv4gZV9WpBcXjt8Z)hk=;Vkyn?|mhODwq~ZLG2J4W^UOVW*fDC)xB#UX{(n< zLL(yfJ>dNN8)yC>{>I?|o?lHZ0qYHq)xn39RB>%_rV(^`MA!7QntgYXrY z+{#Dpp1q{{OnxQ)E1tL|)qk>&klx7RLFeQ@9z34Q%@@LEH8R{$09;y>;3#mCC5hlc zzm|``>A7PIHJ=7+5~&wKn)NSsQ&5+9eF^+o{AFOB2q6;3Wn$o?pXq)Pqoa&wYE5oi$^F4b#^ z$BeLRHiljEOc_1npiB>fBY9WTY`fj}Q!#XO+SLUq)QFh-$#Q+I4C|h*oDqk`63j0K z17brE7{%`4bs;MKcmbzsXs66B=v@;_sU!q%rtuv6`=G};eU0vn>J0-W{13H*Mp$i< z6x1d^z(%1WUa&p513U28){lLjZqA5lRUX}PAo3Tz9Yb1Gd;3`5=s^&mv*Qo@unTyv z0-n<0_XvtkI9Poxza+!JE=l^6=+$bS6iC9y3nX8cqax~i=5gB5z~5r+9f~^Ms!mQ5 z!7{xa1BYC(zghs@z9G7>tk1g6%=jVr+0V7tpF2agn&vbI1_Avf3ZtI@BkK!eWGfK1 zHkvUodYhV#JhYy1jWoayXXd|KH9;R7EtHs8U`74G?BxQuf$?lmN&JteS)wE+aJ#cr zA&c!=I2-5t5UKS0GUlG*%bOiN6O-3MkG->>L(DXpAcgOc`g3JIt~BWLPl%&`d<-CB z^abV9NIq|rS9ted{HG)PzBwx{qgEObdHUWOg;#x9uM$<0cl}HQF-eYct}0-Q)*zD@>8|`D zTwTff4ThNLrKi3S9o?_$q-McKW? ztFqFy(AL4mqbI+@jvWaWJ~!HbFKxf#s9LT$5<9mPsIWr^B)B9-aO~4etVmb~3L^|Q zoND3XY8Fn#`sz6vFMjg)!EOEQwvoZnL_PlvoatzoaL)aMMtFo9ysvnnzk8jl)odW| zSm@!Hdi~YGm%jlM5rnUO{!YYDXhT>nlD!w#+nZA?*Xx)zbUyAp@BME7ke3dg4!L{m zoQ9KRcBy5s#=P>|#3L?_YPr$y`_%e>ypoCI^OimEqzE1MUg82U{VlN@n0y*Nyb!+; zYa)B!v@|R?b}}K+8iK{w7mE_+b|4P)EK6IZ;{dv#H;9PiL3On>_EW_oZmQ|g0`3pWwejEsB{iVhYOxB6xB)atqSu)9FNkR zHQ6Z#?pmEQKzy-}^JAWi#L(2Pa8*SAY}xhmAmxWt4=&TEF|#zcMdajJYV6gau1TT- z{jE3Rn~i1%2>LH)f;Oki?!`|XA*%Y>jt^xY=%D~gO#^@tHt@>XVP!4waZZ7DCDATQ zO<+C#y`@t{_at{*E(+mew)0}1vBdJ}K(wwE$6Qa&i_ylhXSeopkgPvdrYvQL zQwLP&l#UQqW)7TOOCB37u<0^n=i|qYQ&7R18gM{eB z;OO78h*65~Mk0?NQQp)%7B>0{QtEwVjcMNnJ7K$#sSS-qyKD{JobLy+q~k0M)*64v;0h8n;8QpMoo_h@W&ya6OGGI{{WH82*Z z>+*~2MJI;?11u5JNwk$R$OkVG6@@rVo)*|Bpt}6zfQ>$TrcmMyrn(@x_Cz4>*O#g` zv%rF9x@1$II5i)fS(oZjP|Luez~&ky^*@ND4KDra6csI$8n#9Hn&X8J>i59fbrUhQ zq70oyVQq-oNm{ig`?LQsUfka=@H|Q7dRytt4?pU?k$9x5;-MwBkjROZs~Y*DWDogK zQf$?|cwm>B59yhPhDaN=D&P5y6u!<>&Xma2sYPd`p{AgvmBIGPnggTH+}3jxm6p?? z!}+(+bYCPqM&&3>W+tXC!pDFcCC34fs=d{8ZrKS zzGRP$`RPvzCSM2r8t6K@9fbDI5%U@6{pI(6YHUgMK+l6~bHhjt2*^vPngb4ALms+~ zFFq%X5?xJ65F|)nyP|*b zj`gTMA97?Ctdl~^eyeS#t#wSfJrydl;S>`2!_{wvk&6<0pDSDp^m~KEx`kHX7$Z1^ zCleyas|-D3sEQ4%=TnMeRcvCg##9|sAS2~Jj{5}4!^1+z{}$Qt7T zK>`+LLw2cmqlUUmq4J5maRDDu!wGF(182|Dn`(>R0W zk)G9u*Nab7_SN0p`6Z@p(TeI07>5eg6(>5FaK3%}CiChSCnClV<)x1qnVDDw1gt0x zrF-og!y0T}f`Z8clQviytGzn?l{zyamYXBjL8)=9tc0H53|+$c)dkVX_`Um9yBUT# zhlsfzJ_>FB;`}1vWRtZ~e{D`Ay(X<51Jk zT^(>Q#cH2j06p^yVd^X*CH9aG<~pv0|GTzEGgWf3UjAT=lfDtSA$oOUt|5}N6k<}N zohdLTW77FL$*ky&t9B@AN{#s{Nwu%HDj1I1BFdt_zLtBS2)ue)r-bF1_4OVM{COV zn^O$A%e!@(Po^CD>VpgGLNqt=dwdfKLX}0}$3C+p4OA(n>SqtMnZoiO&8CDWf51b$ z6qtUWEpgsGrFG>P9UiO1pm?TqMj#ts3#pIvu16S29Shgw>%Po-Y$7SN5$a=x?Ugug zx&8^k{!i&xr>=+tIILJ>99}b2=*K4*zMzknO$sWHG5#>SbN$I(M&I=cgV7yU6%(1y zh!h7$h3}I!nFcJt7j)O60qn){QFc@WlxpsSZcluik~|Co@@ulBSDa=8r+Fj9EN}XT zdcz)+ej*X;><;?X)7?MyKi$yP0kAtDgM_Lez~UYwEbgULD7EU%T6DCzF_lInu3PXc z6q6A@oSNXlu1~b(VqQi_V|TSmkVo7|dgG?QYI?fO@4y9Y4l=9e4~Ll64w);E49dZL(bu z3f7vBlI`WD*zv}Hy@arkE5m1QJQV$S^l5-f(ly|GDfHB5DLOI#m+M0;uWKc#S}o8t zZH)oX&imrr*GIn}hcqndK!9%|24&-)deqQjma%K1Lbty5RCL3ncz~n* zJ5_%r{j|lir_s?BI=*R?w&jpP$Row0f#+?^tEx&rE=Q0Q*Udml!D-~59ALX zfsY`21W26pH>gn{E&YJ|!2m#QjTg{|7~?F`$qG7>upDBPhFAg$!*oBr+ZnRKSW}{Z zR5;+S$sXX4GL`Gyys>B4$A=($E@xpv6$l+5-3OM0{;*$xF4 z6AqoJg7D6~Z(>Mb-Y}NeZ+e8zSRhO?_XMJLlvaz(riBGN?ff)w+U2t^@Hn>lKl`eC z{c8E#e9}JWkC!xptbcSqU=|V4*c4qrw16cDUvUb#SM=EtE*hNP8X9OdRtjN{<)$W83p%GPebtFQ5%q$oXO3U(gfXC zVCxJTsOgO(hf`%vBW;TLee&T8f5;Q;^f zRvwX%0Q?6OK8#u5%Py5X&s_#*-ooG?B+l#Ua*u;#n)_D~A2rJ-QFrj~yie~Q-Wz3` zy+UM_s2QWxc`b;^X_~nRo3$j28{CJ@EN)jQA#yW0Ezf0vEu}r>P99Z-_{0zSojq}R zxkCFnZC*YXwCoa(agHTZLC_zpqR0WqF0Ol^ptJgAl5A1e9Ug4|6w}h;&B(|=-M(@F zd#R^bP+CAQvkGIQh;P8$%;oNH1YKL-U$-VECX|oUp9x-{QH8o}F#O73JFj^F4F?1h zAHCf}CJ;7F5LGV#WqMa%^TPbq+tXxdu7|}rjvt$3AeEW_G3=91q;M{R?ie?G`|nQy zygm4r_xB%KUlNT@mg0l=o$=>=D<{rygX%1?119H4m6!bc@t&lE-XEP*IJZ04NT=^eZmBpKgcyKt=ED^vfTOOmS(p;Q zCv|QjSUPg^SxDf2od&d}fiH9GkHsV`UxbBD8d&I@Fij6`#JA{fd)-yG^?K|c)Aaar zZ1wWMp(8$AA0no_MLzEi#2BZgN7r+{go1CV!^wrRw@zqsXwaICeB#}^6M0B)-OjzD z*qC2pTN_ge3X*-du>pIVtkb9K1aBA6I4q|$uv|LGIaKv&i=$%`z(m2Pw!W@7^HIE2 z{9A(nxPo^T@7DSo1i)~?wg)9HmoYYFCOrdS2Or1#kq2(4S5)V^g(X9@wsSlnMRFN-msuyGnr13 z>QX3k=+P(0S8I4gW+6zaVK))!-4B~6d%Duc^)c+b{P0M1dXw?bwsvTp{6B>gmomWn z9Gd8)bO%G&=+^DtgLjaR5(w(v8_DalDX@a5lWAMJcp>0@7&t7;IpcsyXn#4v=LIIQ z*3I1voWJN{!l0oU$llZUGb)}Vbni4PV)Qi6lzWxy7k}e{bLbi#>1`(ZdfkA%KFivf z%2@A4GP!$SjO%TpR~XeOHd`%{4%!DFKH%JPKk0!P&bOcZ7;i4DU%+WPf2^+898hM;ltFjCQV%9T(wimCY6Ch(m(GcZ zh;p@mpqli?`xCSY6pweE77BuLO2?Z*(^TRB*(Xfr#x-D0ey$Ni;A0BkEn|!cSb*@k zP;0)dZ8%E-Phx#>I@-wGJe4HP9Sp@u^ZC*kES#N|7`CHNIWNkuxy*|X z_NsJnyHKK3&AKvyv^IN8ciPLlyli+8?22iixQx2~RT~60>7u``vS?bnlrTKqNtqBZ z&hYcnpn)?V%6*zGm*hX;un|M#G4btHbzUFd+2wBI^IFi7bnp=fy%@JYe{UPvlr9=z zt+}f^p#N#dKj{ra~|mY_xl(N zxa<1`6c~&OGe?OZ511vp#0u)zEca$DaK+MUe?HnPN@_&T@4cjn;sHjBang_RUu-l-pXMXayR#H?`R0y^DDQVdW@=R8zcp(H$`h} zX2+!`uWt6l#1OzFe6lSI9o=i*PbzI81Rj2-sYGa+AF0Vj10FWlpUxI?sxKTn3c>j(4Bl$OI(5?q+9~>`Y<48Oc4XI;>J9S;5k>vVj`$dDfiLvwXX_ zx>@Fk&!7Ea8gS8yf+D5VUpJ?+&|tmR@+2o+op^+tMuC-L^bj@>WCh&VZo61ZT#w(u z=0!#(tweuk_i%Vw)$jApcy6+6C*QLIq#KAhM)-dbF|LpJW!z%GwGdxL-A;}AP%YuK zd2*q-F6DKdd$4=YQ-o7}{P9`~geebdik{JB)G6MDXY4wU+X4f8b@5k+w}np8=#C9m}8Rn>1V@tkID_&zgh zW;_oga*0{a%!Mmpo*dl4!}C7g7$&x=yRJ0x1iDHKKv!v`cUffk-SFPF(`=@@A8O~Z zIno0t&~js31S7ZyMQ@w^(VIXX5c6Y${IF3gkk&LgJ-PF=#$ml+W>{cBj2`{H zNKBs!>DPPndWR%hI$nRV$k9Wfyz>DE2xrKDHO@gHUKTC16pdXA{x2fh9*Afp>$AkL zh<1A4r?gB7fWH4yx=GXH?6O1X`_(D?T5L zA6XhIJ-!5@+T10D6;g?|G~8#iVmLWG2i0O-(!Ovv^l7)`fS4Fu@n5Ph&km5JX9}4F z8z>ue>yW_&i6T$jd&4(xA|fMwPPY46yKdd^P-2;=n3!a-oWJ!@^u-|>p`gU>@7)S~ zbg^6gTpmg@T7cT`vU23IAGZV|?*#=~?WJ9mlzZ=?YJB%`&esR6BaX%Ue=;X$Q z*SIX3WT;@MfgX=yw7lx$&(zuR81RGnQc$r0%C``<)6oc`e`*F1-q8r?+2qan#B{tw zFA~h##arjUk2uA=1*1z8ygpwGjQAUGbPSq9QN`vHDo@d1?o#k?&G!ae{{LCmo;w2W z@-WkD_bw6T!-7suil&rqqmJ)oC^*UXMXf}|wCg~v0Q@KUNcEy06SzeH3Q^R7 zIZPnMe53V)3CXabgTo8nbqJZ?(+0POBLi9PUIu$ag-R(WBTxb);;Xn9Une^}W}4c1 zF5pH9_84>7A}4PAnU-wYfL4|g2F@$;+_gON|gpZNN! zMaIqu<4^x^HC88Jh3HH{ezc}C+zPcvkvwP^eGX3tO4TXE*KT+H%QKY9ww$nxR%WF+ z{{-{@yeR-D1xK{M83AMx^QWKW#M@Tc2`VttfA;@JmA7DXnhYji!24aj1b#c1DTwZOAJDtvax3 z%xo?;KVzVzl=@xNM|s9uN)vvT7tp8h@mgOQRrBV)<)lg!&%{YVN}{uN;AqjHOQQIs z^|w2cnsFf5sae%+Ey#u28l6>Vdc!S1j=1Z^5Hv#;)navE;14HvQs(H9 zQFOjiy#51PwB7({(Pg0V^sclk@Tip?rum?f z{IGZou=Hl+=0z%?(?h>Q+j&?Qn46o6UBv=Gi>(QJ!Pl@m;t5z;OfA>Z+PgMCk-WBb zC_mIkdfQkid@5vqeRoHDpP`0k|pv;9oHTJ>P%gR0ei@{Uy_t3y1R1UVokp+JkpvlE6L)QDVe} zC+LU`Z`|(@@whZ1XEDFd+0mKI#pwMu_4C{Ek0&U9(=VU@kbZHWgJ3naHv9T6Sm6gn zmBD&?RGyLRRs;ZhA?wx7vIq7uIKCI|0U*N3_Z1l$P-gxNBu%zy^vf|6jc5!v8s2L4 z|DB?DDe>*zejUNIS2e(y?zi`t<4XxSzzZXDF zf$Ou2eidwWa!sKkhv*vw5LWd29iJm}YE<17umC|s|Mh{T+yw2(lWvUiI-+4i#@Y{b zzDKlwL(iB06nchWp(n#@_pWWwjU(9fD@cF8aTDu)|MYME3Y`DJ%DYxTJ%_N*<6WW< zZa43KVrj2gdagCMs=gjnxnBru1y|QG>f$GO)TjTBP{g+(QEwqXbcwY2>K~}PE9co zKF{NZwHH^UEeb}D5oHV|fwt!gz2_5!KSuC{qGWwZL2mLUsQDQid%Of?p_m9^-R})7h|uVNMXHzeOZZ=GVCuziE{RlcD`~1R z#q(Vu_BPVrqEZNNGJUEpB{S7p>+}|jMrf$%$hg#wU;4mb-%P_Z5Bwm7z8n4KYuYXl zP^42k-x7oq7#uw4xW%Y}^xW)x!Ybdh^^1VpK%tw{P>~LCLPA1tT7K@CEQ_aqxw*!R z7smWtCq&)JPn$XS<4E%HASJas4M}* z3lw3so zLfd<1a=K>gPv+Fy($g>L)WbfxpMcgQ@cGY^dwze9GzM&*@-4ofG`tkc1!p4(o6?a1sG=Uvs?_@C> z?zY>IACJ7XadZ9D`IpkxY$LhTlw*GI{d8m~(5!$s&3N(|MaH>K*=`nApWY0}q%4`^ zw0~-6Vr~37v-0l=51Y?uRX6lz=o(#8`QqTavW;`yF=-a@9y$uL)SU2ya$V(HP@7y1 z7|K*L)z;0Cyg>|?g2MkP%=>&8F9CheoWdvLV07oaU`{R$!CeBn6R;)N++{CM4Qql8 zGCam0B3Hcxcx=ow6j?KX=g^5 zmKYZZ7{AM5Eg9tH0D(VqM^iPAqLG%7@JtT(?U=t@kUK;k$|Hofm}k()E5X5c6l&2O zs##aj`L%m{UfUY;Dxg4(KIT#6pVHJnJ^5h+qx016eHr z!Kd^;qWs>%2%O1dK16(iIP@6{>Gt{KC>|SM)UWOrM|h{fY9d(ezYo2dQvwYHT}N~R zKNV2CF$?XWgivKQroyItVVf1;B$TtQuEsxqq&}L#!i=Cq&DH4hUlE{2P^UGcsOLFGTLjmQ%D1QklcdDcGCC(X92 z99mDDD3)X|^_BRVJ{KZRv7PYi+vKIcwt3Roa8s8TQcb|)G-iFq>+tQ}Vx%GR*F@iN zcrnS}FT7m{$;&$FJr&;zeEqW2lX}m2l|b!wP~zq600GHDoAGsh=hv5_Ei6&qT@N5^ zZ=X*j3bT0vVF$caF&Km=m@X;O!1cXV2O^#$#}0zo)EAS7WRtS5S^E1aOEW0#cbz{yNP!t z4JX6Gll)aj^Uq*P&~xKH_QSuSt-4^ib^fph{fa3r-FbuW;Qo?z)fUcus+?Qs9uG#c zI7KXpJ^o|YBy>o3^I43l#J*ehi0H=4ua3rDGZaPfYsELCV()NlV~P;Iu51n;dYC1! z=6MI8!5@yIrozqtHJExj}jTqf)MtAI`Ehaq{o#WqDJ5 zXC6|v-j|k#_EJaCLUs$T5gNC(W3q=|zRp%${8C-Lxc=?o3Vj!*#`iafy;qxWpPsbg zc!yOlVPBmsV#qu{RTR7=0n_IyD;nS3dHjUKvA5GA-MQ<(RB@Uk*XD6LMTPNnql3<-Ey0wb{Q!f73(S(>x0&VNLxo!4DZJta z?H>$3g{c6|@PJbPC~oV1LeE=LsXLRO`)^JDU~hB!aBp)awYisc^o*68y3y&ZuF@As z>C(Gi8dE4??JR8b!MXVMBBvfgT@YS&h^#7Sv`gUVleN(mJPV#>KPG!A$8KVYD5!-k z=Ybv05ei)wn5v$qFUIs%#ZP=@@fb~E>k+4YU`8OLhEaG@yGrB;Lr(IC0P=IzM;vA! zfBqB*wp9$STlzG$6rynR%kJA&^aoa#C#`ybr^ZojvfUew)0^{K)q@tJd7*@KF%xE% zCuzsQF>kk7H-&@;#c|_HUnuwR4^KdY@K=afBmue(=0n zJ$;&sd@lcR@q>cte1ycb{Cldf-wOK87su7>{&_N1?+}Y?5cDU-#P=7&d9*b7wF+p6 z^$7X!GgCcf&INiE(Y){)XFJp`JUJFcr(7<#JNJ`!S2Dm}lg{rK?O7S1(O6k?Yp%g# zf97k)J9b2U18jaJfHbnB=5$%XGg}vrIs~Q|A1Tb+V8oR7^f|n>dQ$MRaYhC7#z>FkwkR@HB;QPcq!R6rrikfnyd? zLSK`BkH7apj^IyrLm`iVk5|+(>D7=5Y)EfqXND^+os0Dtg*yu20WF(VdvScjj-9Xi z0B8N=a$6&M1D;@<`lJ}idmhL=450^Zj=K^-x`rW|ZvMt?SJnM;=knZa@T>I4RN2qW zZ9Jx_h2`}Z7tSOuL&}}|@2h4$D1zUyFmhUOIzo?I@_ES!qP zp67r_ss0PzE<~%1EceHRR&zhXf z(S#Yyb$Fp2X>9}#gS z7cM*FrMUh$56{|o8C|&G1wDz~)c3WibK#+4J-u!G8LR116tvdp^v0_NSzP7|(ylmG z^&%I3vMff8YATEcm?=G>Y_|ur%G31h%s=HEeQtQKT*&RkdyWr}?QWaTKdQCQ#i&U> z>h(p75Y9vRqIrYQxjh-Pu~#0-m*z>QJ-J+0UeGGuElz<2KZa)59*C-^NF^jhE_8Dx z8+z}6pirRJ>D7d!;02+7@+-}R{RK2uD67zIsEF_V`Glv2hHckp%@~AFuduVOH+g0= z#JfIse*X;HN%;SJLBQ|vCUvco$lYC#{(pZ#Jw3Z`;=ClszGD>zWJXpQobj&+<3`gb z9&kd;)%;n1*d9iDjUQXDF2jsS8)igy(gSu>C~O#uzg3A^cN4TRDlXIw-eM9c?osLQ zOpZm__4?NfSk7&Sc$h`>FzP?6dv}uvX?nxAwELhSKs7(A4?~;ifl9X zMWFV(&7#CI%5NYQ@xs6$og~lVW_D-7;YCKIKI8r&3>)Wb7%v8he?9bzHWwIP+z6)G=Y3IzkzeBq?Jt_~Sa94<^^h5ThV)PFmDSGn|ree7fDtfz^@f#K?alx$;CsU0HPM= zo&_hzfy?|%9g%HVf?**_NF=>m(f(C_0L?_|H8{|BFm1~o?XiEclo5}7&iTCBhbmID zIl03!{p|@usS=N*7lXBf5wNNDP7*(rn2j#9@S2v4PS;xri(2X4XPFyJpo|EF+gc&M z@z*RfNjJ<aAYVr9V+wEm zc*5GtV$n1Hi?pNmAM}?Ohj}J8voZOBus7_s!AU$y>CC;q$4 zOt~1*a?>+mefz6V8zy+`j$L6~`YYWD+-Y{E?pN!k&mUz3*XN-@(KnswgM)*u*8{Nt z(S!7+tx&V;D^(;6O}@EDHR1dM60|}g9qAp35FfC=o)@}sDpwbfCv^VS0~5pD zq-aC03Uz;U?g`nlRsF5|V*8ZwI-bw-x5)f<68MQDb_RyZ$W?Nz?SeQ#&>Qx#0MW@` z882h^i;75P`0o|WzQP}h@+;K_-8)b=b40ey%xolTeI4M1G`SqhlmB4mZkf4ryxlkN z2YAa82`V@16in0fGJSup@>BT8;W(Ra)1AG~IVYbwh*Og^u+Gn94-45e4HTw?lmw7p z5YX0Lb81yu_yK9zZv%rfNXNnyn9$qn#V6V>$HOw@n$xms=Z`qIw69E;e#P6!;17&FfVqBkEK zw<>z*geL$Y87vyEkcN8Ief48aa)nIf0?kaBef7oU>kUSOz;Q8sUv&HV-FDacsD+%3 zG!j=p*oxj$tdgd{0tZa zF@RunT&#@9>X&Lw;4v+?%H>Gz<9IyyTD4v7hHv__7=k`)C~3%mqLAO!mHXA%A?wp$ zU-x8Dp-U%cIEr)KWsKrFak}nU_{O1LbTh@(sl26V zkvvfU4%_RSx!_3(xgN{YO6+)CuP`2Vw1=gJ#;PXRKEsFpY%XG-u|=PUD-=R#4?)xI zvFc9&pvLh4_@y@yCI1>v6{dn`FmeHIC#>wN=~*k%1CdmJq-@itMK2%@nDNy+>{q3W zRlKh8i!Y0~Fffi9nn>FEgF|6XiSzjS)TVFRiQ%N@-114{b1O1~&0;iyg`bCguO`|W z&+*ZP7Lb?EdMB;gCD{d4F1l<6CJzn2G_wOS{T@Uwu-1E~3+JDdP=1_j6#xUOaFc@% z5H@yk-%5~YtjP=SvW_2DemacwmVuqR13KUCFxZbf&eOSa8s=hlLpVPDVkK>w%HrW| ze85OxbV{KSC@t2E?6XAjGt=t^kMo)MrSQ@>a@~J^BYUPTfE*i}v9_&_IrT&5{fGYz zy+#N-K!TR^k8glUP$2_=^y&^EIb$%~Bv#P|2AHa;(B@vwa_BppQjPn;gP z7VqaQZ*}?A_CCc^4uo-A12~xU|d%!(&`u8YFwo`(d^5^Sr~= zbvdUoGB!47Vnv%jR2A&8IVsQt*)$r+%B4OU($0Fm~uG>=|qGuhmV*oo9lxbs`I3MG&FO*!VLVIA!S$N9i6WpwdHSlZ#|%Ec;3jr8r0_;{x~Q=A@f5$nA!W%c zbo<2-!+IGX#T-=VQ1x9l3j`r4{DH{aQ>n4P{jk(&_k1*8H?(ib+u6r=oH6uTIH88W z8yP+GtA?Nqz0g0nNH}|Y`BSSXG5>soOg%$Y;gubcxcQ(ANE6~Y))MoJTB__;po{zZ z6QM+FgIW1+RzHw?L9^ntGf4ED=f$1(W^dKPm&tvE;Q~%~0~QwEh+iEyX?EbU{?!5~ zU;ow9^{S|m&5>C`=sL#sYAgObw@W|8vc^sN9as93@Vx_gDuqAaqMFjfv5OO$A%G@9 z5rojQsA-B?d>QdPmxkE zjSnvgSuv{4s^;r^aGJx*JKhG^C8d%Aj`qak86F;@>TG&vu$~Kn4x(bn=XV4<(rFTq zecO^Y5esVg6j=Un4`v=jjRClx-+=th^;l`uhW2~K(HZ6i)?qzO#BN5)lF!FF&d2-= zaQWB;szPcWrH8sJrB^l&i76SqQP2zEOjfObb74z`fou3?vq=A^kU`;7gR=E)EI^VV ztgtp(x@hEZs9C4JNVKxH6cQ%gok4{DxFpM-PU3c-u|;TBe%EHRZlrn{I-gw?eSbq% z|2R*T+iHwwUOFT=_-Fh1d90#3|M5`MS>Lb7c}EutCI=no85eq1R`rRb=T_*Av!6gR z$Fyp@RgPhrCO=u(`QxHJMmpO1*5foUCm7S>aHVJ7#r1UE*NINy%JCOse$gq>Bm>^gN44s-#>bm zbSCRCAVXR5RJ49=sD&j<5$grpFhR~16Qcgl$qygI74{Q6qu@}erGOR?g2;E`KlD?C z@E}6lH4h>a>aCosHtqeZtYKxssf{%`=AP%I3UlMjR)&iWVV~2i)h=Jz82$ETF<=TC z`UE{N?y?>s${FRESC%CAwJEO0|7|*)>a~!^^rSsoK8do(VRPhRaoxqE#40nafub+n zS6l2;F74X}191~KqhKdy=BG~|`Un`thHZVR5cL^#+_o9u%GCLL<{l#In*>7Mg9#C~ zVDA|~02|Y-(%kXC!ixVL|GU}QJSfbdJEL)I-L0)CSoF>=!8W>TL-TyFmHxaW??t>t zpP&Jo?FEKPt+gV=0XvroX_Mqv2z4423=ze{5E0JiWAfUofd$mi1Y#)*@80@u#+#SZ z<-y2X{+ayT^#PdPKbXYz^R5-fnT8w1p8fEDh=&JlX+zalKoPj6_GtkW+GlR2lfRQL z*izxpT{kuTpLrNj#4+hJx^Wn{YYr?MZg%WO@No{5K8UsWhMkF@nCELoms{^4&3i%$XL6Lv#XBdKp+FxocYri`{C2^Leka6cNRDw?? zUcs3ZJ0~`QPKRzx#0gm5g$rK~@~%#WUfDa}?epco^W7t{0f#47f#hgj$b3&r<|Dc5 zL>l*80H&l*WJ52~AMUxFX}A}`wH9hk4m>wM#9>*#?t7gA#1#w1vVH?BYuOH2p1#D6 zq{nu9924%i+_bNK!#l_QxDCr^lqIhPncKhAZ~QviR$SZonc}tY$K?HOUp^HvK~H*L z6U#eD+XS(s8|foH7@~rW4OIsAll^fRB?LYJ1YzPft%9=L4%X4S)w#`juvb|w=rgF# zL&oHcb->`HHinKB+xP?%4_Y1RO@v|wOaIx}B~)tValPM~{vx6TH-z8eYYL+A31!-7 z+}26P3#;xs9-93kvq~Q3QIBZ5&Z8bf`Q`laFCU3`^Ozy1_9ifcH&WU%rUxRFNPUoP zg9`G{=YYo__YV9=l^!uGXFD|cnosKbSU6SMl8x1)UCwwCrAIC7m3|4=iSXL77M{`U z3q!!BR(g$2%bh$eB}@Q|bcC=-H!>|6Y&^6*(cuYl7>A-t;vaEd;?n}ZLKbz+G9T=r6 z4Eh}jasGvep;8dOYd=DoJQ7XguEUkZBHdBw>Va0P(FAA!e=Xzm1`txgrc+s`-$cJ< zyi5Fz>vU56Y7#nm=PJo zz7ymylMfMprQfrK!8dOsTLQ+^=`cZhyck5GD7)3zeZ3wvn3zL= zQ+Pz(in%}>+Uf&kldm*5L2+>B|5762=or1iSQe8U^!KkKU)jai>K5ySol5T-+(px2#hH;}CkYS2GZwpc#=ppcZkE3?RKPF~mv6ThX>5?GU0W! zrDRTylHzdA-^1;9=ahS1^XT%lmJuYJo(D(4XFi&`yXb3HuI+nd@G<~K_5zRr%I$K3 zQlxfJGGH*2|8M`q7fy+q#r`mihJjhu>m6H^)yFX`pI-tHfdtM0dIxS^ObxZ_hh-&+ z=CruiZ2KW$ys0*{NfyP&h=0Pi$2v053xr!zHD|&w{GFCN0(Sy1usH#@Ad=*tyq5ky z%WL8rhMMJ%nXO%)kg2Gd^x92!uv?e;`fOpudOp3Jw>U%cj~??$zf8#v%%wt0@z3Rm z@16$a7mK&~?-&iL5tDK2@k#6p`@jk#dfK~&do1QiD>Kx?ggz!k^r_NOG@GkoSM(_) zUETU)uC(#MAWkrlFncTxyG_&^7fU5h>dDv=EZAOIP(jb;!I<0Mv?fX5_p6qHR)1{f9& z*S&mfE}qE-L=MA9iX5#`BW_%+2h{zG$6iwh9R$RFuwB*)Y=(q7U!@fjn>PQpR?k;q zk+P*pc@UISf>tGkkfFQF{qOF2)Rv91yC8pa;iMc#T70Hhpj%ONA(LZBg+BGQMA!8v zTUovjCB3hz)+X?Muskg;_T;e2&xfJnP=ircj)h*J90!U7I;7vx`Zu8z{tOKf{$NpT zC`&Zhptw3^aZ8qPCO;@nHn)W88R@<7U3;iYMXh-XQc2N#HgQD5a;2Qvffxi)VusDJkZg696JW?k*0#af)u39L(0aK%VExAwBe&Ki+p-d%|f8tX!WVX`URAm z#H$FZ01RjM(b{eZ05(+JA!*jAnAlLZ^I>LmKo~Ia>TygrZ;gArtFp`p`gZ zqa^aPx4(Y+oADL*Gqnn$Iul;YV+4~b@FP$#9R$FQNpWkXU ze}4*_INzmDXGjb2SU+K4`&N4W%Q%bP&&g`HeJVrX@Qcu;KDuZD2ak!qCakP0m^iB} z@?Q^JHTs3ochtl$Tb9-_*>2SURWkB3nZakXIn>SCvvLk~;3l=!Bx~25)nk;{f7Tkb z!QcHqZ>47FR+0l-3Ci97PeG*GP=^Vn&&t?dT0q49=P~RaS?$o_{gh=6^(vfvpWcbL zmzC|-fO1tq+|@W`msXP#x^2UW^$46R=kr~0pC3-|!8RW*RHsw6e~k1@EZu5R&5GHT zpe4m&`A{vGE{H7l{WisTJ;@BQx3-c4cShCKd7zs91f4-bi*h89>Wopz*!vz{v6~#8 zxngvd_5S|Qw$JO3Rpyhg&H7LGW4HC+Jbo?L`2NYXK5Vf;^vocL`Y=c|APpLmgFpQF zWQPf9mJ>z=(;2K8+2)iKpta4-c)@v!JnoKw`$&1P(Q@kQcFEg|^4;}*{|Rd68p7k= zdLlL`TKSU)G03c%1pxQVY-(DU2*wRa1fPKfYfc8moLW{(8W@rR(6brRZ+j{L1y04p zQkJtreAUi3y9WFY!zhZ?EvWr3cY21miCGXzh=o0-^!ZV#ZBjx9ObFT|Q(9OE2I5Om z(;EM?^Ctuf2O7qick>Rm;v2i|T0u<5E~1Sw`o*U_%pZK!AW1lpFL!ifKJ1jb<)&aW zVY##*yh7nBT}MH&QoU~(-fk$q#D4V9ZXwAV>$+wThkL;S)cDu3VQt$XEBY}^r@at^ zw;`nCx>2$lh>I$bi~vYRW24XsPkb4wLOpYgB&#$&USIN`_Q(pm@$8W6&0#Y=(-|IJUJIi z5i}&!WG=&l=sx<}jcQqxV4F^IWeni| zW)B(4aU6o&%qx7ShjrG|pZLEKPDl*GdHi`m))ZxiAsxp_VxVJ@v#cjzKozyms(#3y zjFls(`QOeRV+VATzDANfRPVhh8dg)$4y|K+R4clH+1<0#z4Pn?o8N>We_*OuS{IQz z!)tI~oB~|#JEi*;g(2m6b#N&>*UqUu+`EE74Bo+l73MfmXaQszYkY0vlzrALfk>OD zO9f|;2}%6U=v^&u@dZz(g9fHbXV{ztDLV}OueZntoc`t2pZOV)1>n&Z`l<%3+#d~C zb;`Z*B9yan3z+WD|#-y6)4`oR|mq8%^W1*@$eoS6AKs$Q^gIIDV%12J8%qwu>DoEnD#U*)lu3Omn< z1Psk_P}|%UV6hOa>a|V`yZ(>(efXMFZ^j8#n zk-G6%?kj2SAQU1NU~gW+l=oNX1Uk71?%n#u@@3SUyJ@zIvkO0r!{AkSrVH&g!vnFp z*%95V*GdqF7FPt5)>2=Yp9VBN5km0>mr7(;5dBkGfI=C=1xgZx8Zk-%* z)SVDMtGFm-=7s^A(oqsj%q5SE5dT%Qu?xM;4?;}qCkfJV1@8j^sOQ6)ZMne9ENW}I6b{Dl8G@az#*7W z9C8K*+l3eWOCEo)fpqy{0A?Pe&;N@5l0sJiAb%Z~rLN5nvvj&L_C&}Sf7^)cByILW zw~_U=-!E~pS{pflLvE(Sx&`JceEKtBIh+cb7Q|tn6&L&89MeMT5+_B#wvTSms;IS7*>|IQ3=AmnW!ZuNEyRxq(o7 zj(A+~EQ{xwXE{@^H3^9I%|ad-_}z*aH(vmkd_3)8LU@Wq@P4i?6`e0Pn8b7Zr4j=2 z6LuSp=J7+eX1##qAkYecUaeOlJN57QOanf@Y3+66AGx;S`rmx9?fJOt3wjXQPF0IW zY}$B|M?Zr>(zP&YHW#CxyOE2^_zy4$KTLL4o{haV!x*-wpaDm>A2dvM@g`;6#b7n4 z{>(PXg3=?6BhL2T*Ju~!-9h!oXMNi$4lPMxrUOY5TrOK(xQ1Wf!E@Ey>Njy(*k61G zKww$Q%JE>nBx;T2GaYvWi%HK0(0ybrwbhfB$)Ws(S|)abKCR{`a2CMe!l_1my7R40w13PlZ+ z$l3|RDLdnTA_Z^rktei#di(fn-#lgbttwpYdH(tG;TjcNcWKJW)qFJ_46lnPo;2Nw zk2S9%Tzvk;P8K#S-?^%Z2`~R~bt-Bi*Bo-)Y)O+gZwVxk974b$ir6M9fD0NzW;S+A z80GMwF$&akJiqT60(E};v%ghpb@pCFCBbS#DQ;#o^Ww*|F>_C1)`OHy77?1wb@v6G7Yv1h&+mBXK^09PO)oMRx7W%d-nPX$L7YL0stfMOGab1JNbjI5y$ORcvVOB*!Z@*%|P3h3&z@hq8OWz9x$lhLU_wi! zFpc_U@DhzSC@f=+NM%%rxUXtvKjL=`K2yN;6Qz$(Ny|E^F5%iM^!R<+m8eKKj7afK%<$9P9yryW}IS`1ThL^>7OFHWh8?pdMQUfCN}&98JcqN*zr zYE|Ifr(x+JRmAa?CXh-v%cQh5yyLq$>(Y-&T}niz$}kMe4zhzm8W$oBVAdlD_?X$v zu2a-pAeJXMyx%J^!t%^=iQ8pt$7QS#X7@eqnnu+uS87OT8wXC{+wYE+p>6%7cOTJr zhY_Fhj&A^wn9{9`igXT4fBobOGb-5c(5bOUWZ4h?vTX(y5P3$Ts1izT#+{d`oFtQu z%`l7(pEZ6U;FqTOPIT#iYYre_iBLPvYjsl z;>Eg+uz|^Jw$~|14RI<{33<=NDIc@ls`F1ARZ8-0d&#*QU9T9_dFeM{pP6gv#D01n z<(3CCZnLdxnnZUjKN8~zcsGJ6+RsE6CYsvV`NU$P&fFt&0Q0KY#OSH_An9I;8d)Dc^GB0~zA}i%%Jwg(Bk7P|{ zUh`$HVzc^mTCF^L)0{tz_E>z)Mdc>zT4EMANk5t*^O&ML<=a}<+Ba;Y6+DwP1t(Dt zhQXp~G^Z~!*d{tGp+24q(ci^#Vl;T{zfO4uSCe85=uhoys|GKf{j}joP*ZiBfma{f z4AK@a#Z6(h(_f6+$hgV(`8GM> zi>{DJF?y-t{PDiwwQq_x{p*bLY?z+^jEz@JR#4I7|a!$ zL!3_Obpw=>pj;huZ&7mcMEKTlpzbl)qVg*i`K)^2Yzw3%Z^d ze@ijS@*ms-vPS3wlGL!g!L3JLm-R&(H7gd5gWe4)Jjd@Xw`Bh0s4W8Is(v7A*CaP2 z;RQKLo?#0KPFgtYgD7Zw zE|QM1Vhlq``w}>AAouvALldI+J1ojuj+*~oEf+I#sJYLeGkxmm*l(Sp$XoB~jx;5F zLm3jWY0rdG=p*F5Y{!l<91XA`PkVK*3W)o_K4TArRG9Goxgf1X) zQ@6lF>4Q$3CBdlV&k?ZL5 z{5GDM>tXvO{QCXwcHI)IVX4gS%~N-Z$f7CYLkZPh6_}#cqO+J@#MVBY25w5$LgCiW zQJd6CxC5Hu_V7Ob0&yzd5q({?Zl>x9-)<1KW)V z8f#5AR@qU1A`a5C_aA9&O7oBN2?$>*POi?81SvQMZ63ScWc>)+BIegux!?RgvYOR= z8Vk34)uQZJSHH2aYZOaZ^=dd&>v>=5hl_dbQ%1e}&8?+U0WCs_2a$Tr+k6Y|(LcK8 znDJ-P)@))u*iWK#$T-r-sl(T?2Pi6Co^WOI?6#UQJ+7F!{TOGh*d(He++b8HafLa- ze}%O&Sb8uMhoHE69+fXxMlAh<@?I~I-2hLzL9G;>-(kF+{ffZy?FmElSS ztG8m5l8#s1Q%|{dbRui1--v=A`l1^^LtPcmto|r1Sy$Xf7jlYsaZ(8=)@Qm& zwEBqmFrVF$nYM5L5Y4OOirOaGD`)19!zYiZKGW>jIxTnU^^@X__LvdDA|kxSH60y$ z3xm|wNFBU{9Q5oJIj;}u+&O#TY|4`;dStz_IkS$9k~~5)x1%K|GqTyFFe`ngqe=p* z=7$JeL2d7+Wh!#u3%M1}oFz@E75we9ERz zTK4xy*-~Y2l>`nJgAshW?8A4KF+hX?!a{fcF!Y8F=;tjlEN!8i`a z0`-S0R@A-%R6DPCHT3>xo8RTvIbD-9L=|qo>DJj3c;MJ97YIQCuI*%aKk|<<)eI<8 zu{q(@7Lp6s9DMr8acmO#_r&TKPpH=Xdeq-D$tMTbT7&8&GDRw#1G2dA0^=@%@lB(S zu}4?*&hyPk1k0vwaSX}$w*CUElp&$lk5qYPxBg}$SK~W`=WZzYg_VAVee#!8CYhK=09;Rh1h-EHgdz$T_eBb;_ z;v0JWbBmPmr@YQTR$a#4oHAdwz4N+58}wmqhOpq_f^LzOLOdGVBvDR;7}?y5X2R>x zo&AK!B2ye6se5Xab73q?tQF?NMekBM3_n`cw)ao)GWo=_(t#Gtv5BVsA(BQ22;gd= zIM(1MyWj7}15-o465BWcv7c#{?A6uMI~4!DmB`iGDP_fg1a;ZY$WfwNgAuMgr2SpH zK-YZgv?KE{U!FN6M$UIiFs4I4|69A87~1Zp*r>zxo31il&Lz0Z zFUT7$lnLkE@QVVAX+BxuoWtKE^Lj#pYJ74(<>Ug&EyNUOBks=hu1zTj? z&*!3qUzW<}Gyh(!AEnywChkA{3gos60$`4b+*vXjEVeRSk6{C#lQL{*xT7CJJekK~ zqFy>tlpCHY6?<9>Kyqr-@1j@AUXln9ouZl-&Nd`N=fYRw&zDh{bpv0A;F-`#%PE&r z;_A8kjg3}8?6Uw7duE^1i(H6)slqlD7-@$sYG8`%)0=*q6NY^6lB`~ELn)?zBoW~- zz=#hGQR&4RwVO2-W-X;;fbC^|~7d0d3*$g)RXW?`ID=+_d;cpRTKd~X5FS^)H zJ=cVXsz-lIP5&iqSCP&~ev`8iDA|Zs6UHQMtrcQ>dZ)9&nEPJoXFE+I5PT%h7dFq1 zOxg2QePdKx(Z0%PFHd1IkJe)Z#Rv_+Wgi&sm3l~??etrffONo{8w<&9KX8y&b_}5lBi1{eyvPe&sam6A3h9UI9NBc(DL_} zA_b9GTt_eqrfY}%m)o1sGJc-qX@rRD>PXJOtkRv!Mhh_*s!gxzXTB8<5AasaP0jn8VB<`?fxJUG7hBt);Q#3~-a@twD-Sy2qYX@JNobAI}xRRm4 z9jHOgjzGp3sy7{_2QIQd7r;DyB{al59Z?&1JR8>5KP1qR;xb2!<5jS5dwMcc&8`_?tEI78j zp27Obh{?IWJK#s(Na*))jb?kl%R;^4Dw)>b^ktT*oENO7plzT_6sljzlTHsqvOewj ztSt+Pu=Dm9>&@r7F9<+b|IA1}SRM2$a4@{_Q`5Rf#-~hSZ5>NzI*XsIPxB$ZaFA}b&(o46e zRR^nQ`j2%fFk{Yb<}f#E1>vXnza=HUFhrg#PWi1%J^CD_KwRv3Iw=$^mWDtl;Y=QEm=i5Hc3xqvlL(7XEzH0I0 zT`Nk5;lYubNbqo{v#&HBJjBwtS!*P<; zibjS?h6WkvCc7KBxpm9=Uh+RKG!#Vzm$mU$GerdSTBx-tJB zNoec%D`J6TYnU`fTX#v`MZt1~zV&p*XfR5b;2d4(kSNawB7B;-#sdgAqlibQ1i14My*%_sLP{;G{4D$n?$e}J_Cp92R10-An$I7 zLhAPn>Rw3usT9BaTNe3oxhi4=XhZ`>D(a3GQt8P*Y@Br3!UcMx@?O zi~G@&Vh!hODZR%$ZOT=!nWshUuzXCN`V)?hHD~Ns?fldYb}AB_bD#^abt@B5He#7% zeJ2f@SYDWJ5It>`#SfA=9@J_3{z2Q?zq+>VX9x3Vfr%B~rYT;qo|oL1Q}${GHu1ERtKt}`fq3|*_b@D8@|N~nUgu6Ru9DRil5k<51sd4U6SUy|GKBhV*FL5y8q z0><26|y#I&mp~pzc3VUW%Ads4kx|Q z6Du71IUDI*9i9--(fNi%V7K+-KGPC~e1fh}E=AkvzbmwY?&@{Q#xUQ^pvNhr|7#A+ zcCz*2n;EyXu@EeN?FqCsX*O3Vi?-SZlvT==r$9QUtfrRc<#%(SUQfdEn|BGtm8dJjfG!Q?9$!HbvX5Z*g9I#JB>#y=28F0{ zGxX#vAcsCPD27?j9v)N2kPHXWD8$Z)`ET(<>er7>gDsMhcjrnJxaRS~O!Twb{z5*1 zoTU?k);gQiSm>aR>HeAibB|*en$jsV511f!UaXB^I)^#Qw!yzD4t`cZO?h;)$LIlt zjMSA*5{N|R5O<$mo9gD|#V>y>DeV6bGLM0Wf0{7{elf+G0H6ivNeKBh`ib zkzmy|m17(HVqW#$Kz?%OlSZEUs{dQ99pe$UB15Y9y1mb>`5ZBM$%LY)6b>)ns=(cXV_{xe|T1Wnr@EGwV^0H)DevPHuL_ z=ji5?q6T2c?EkZ4s{Y%K5%&Z;W*~X-)1Mvl{Qqjl03$a!4Cefr_h^}L_&x213(y&V z>bHEWQ@>=Oc>BFsABKuSD%Vw|`!T1vp*CXM(b3V{U$>~~E@=V~j!$)4#ruot{=IR2rC~ zkVmuCXy0OC`UC9)ewMXh&Cb zduf%ZfJp?82w_{)mpdO*QZ6e5=2!vB>iWSr{3dgO^g6>dAQ>2M*VDy)2}^&AWyAj% zjWU8wMNetIBnSqYkUjRvgTOjqH%j;8A)Fr7`yFmHj+Cbs!>G~TeB>cxPel74`Gug)OsWKkB=4EIPWI>+cP!-a93sZR5CaNYT*9%dO_@W)}|+ zB}l$fY>)TWI$AwIAP#8>B2?N?O5(H?`I;#PhCqp>+`2}?jY>i3fYEiWzfCwH;3sf( zzSN%DOqZ6M_{8346TYfN7)g;ttke9dM-k3@rUuTT_SToNOFOHSYxN|Sqh~b$Cy2X4 z(_ISk?hgv6GJ6E zp%f|O?n8&+_ODgZTOiMUg{uC+w3ExnEgy#Szuh7)svC40trd9ozG`2vpm=*F%%tNI zfacS?t#727FpS52dzlz|VLkPMj7&--H0s5df_A2fhqS{=v*XQJL6^7D`sOaXQ|R&$ z-VgV9tJO<;1u9#2sn4gUr$ZBqGczGi2sqkr&lkc_7t+WvzUmfzldTahyVX6P^Z#B} z{~}|nudfeWEkP&ib??=5H)DwuVMq=9Z6GO#N3S*gyWZmHG$^q~C!>czDbMx>X>3S) zNEtPVQ&2?(ekaJ&uKx+mllbLEYvjY*Gkt}hi#r<6n(@!u4kFEXe)#b0%l@MU=LSQz zerv&B(8G90-=H+{#q2v+KR~o%ZVrO5JgB$t8%KN!j5}|Byv0HqhfWE)n=z{y!iFCF zvycL8enVod=Wos`KXIFvxoS-itY@fFn2|Jo@&`lv;-C+?-OtKXxXq)uwC0gPszCfZ z!2xUVoAo`)4)TL~8+-RqBuX1f4>jt88*ZCw%T1h#Ryt%^B#RG~QV}0w>VRc{JPr8~ z_yJ>tzYPp@O-$?RYg!RK~Mv~2PbGdu6iMfQjbgyzU3ykGrMFNMjLuTLU8 zEkSeB2TIUK9e2myB-!4KOBS3^(ucBJO`)C7IpOAd9|&vF`%+TCAoEh9cSbKy00|k6N;GCHE(|atF{b8K0dhJPI>>DF)9{VbTCe#CpTedFFOPGE7pb zl`y#z)=sH!m8tQmUekITAtvy{4sjRkv{bG7B0jrK_;aIDy=IR+Ta=9YdbkJz&S_>C z4?$x{`RGRsK0#+ICx_^Sgs=ywyYHEF8#ApNokOkP1dWa=&3T;bUi@5*nxNX3BDIFD zKfxO&(SO&U)lc=BV<`^%S4fcPffOT#HDCia$MShmEF94QOw47qK9;4XZ@XaT1%`>IvJD2VJ8oX{3qjoqWVv@M%~8D?=RI(`+}LLOZwh9CnZ5c z%lert$<8>KE3nlOQoXGD{yX}u5%PmieCe(Pgcev|dJY3?zxpoC6P!)&cy`2)uY1c3TUP+|3v)yTb zzn~|Gv&3G*s=;lkXm?J)AL=O;$-Q;aiYRy%IO{3|*&+o9od?{;_74&THs*h%P2(r= zDRp*om?sufL@9t_Nvj2vO#G=Be#@IhafZc4{O_GZ56Ny;airQd2HT&^zt2*Y8~cXL zM*$mz_ILlwV*GFRKbT3TW+Ku!AoY9yyJwfF{@(vu9IU_cYPaGQ6uS3(WX+L-LiH3VRR8I&f zx6<$$_Rk{ry!O8`g>TliUL|O&++%#_ZoW#8*6Cd~e0io0L$8rtn`d425IU;MbvXxj zr1@HSs@91<^=dKZ!f9Cqk9I9k)j}Z$rntWTDY*72q+Ag@x_4W1i0`@>&BsYyG%K>ME0y~jl|FzKNH;F9D2 zV)7q40)ypan|rec|39+;{`UC9nG7$#%>Jwq?rEw8G0W1M7dXjY?Ty8c5{c~AJfsi( zVGuWU?eDETnHV+69p;qd%e*FKdCAp`U(xaf{y4a zbLe!XA$jO@r8oSA>aazKFq19%ekGasPwVlo@Oe7s)ObWQzcjrgRA()4d zX|I-ZVYxTMUVr;TyTWSPe$M6owtguyZ0Xnp33f`5<CiPc)X<43d#tN*{|iEb zzFp1>?Mw*E^ktU3fY=6;Zo8U}!$jPL^I-CU+o?YoQ?@b;l(j>t&9Upv9>^814~_cM z1Y6zfw4&B7?ryKL%*yn@6l5~Bk}GAEK>D^J!F!dRL}ht?Y+cc=%6LX?!|(9}8kMh+ zywP?llr&4eF}MIr(f7dchkxC+P?^+HM})rd{tuEj_3gQz5!s3+Wf9wF_HYAgBp%r6 zy_$b)iyZoHM_b0l=w+{(6~pwqS4OR0T1Nep|Q0dA!wk!zYftM#?Z3+<~?W~hnqw5Bt;3hJtSVdj}^gnbO115uXN zFAUsXQt{7GQ?RTZuKEbs%yg1X!9xpl&a_tWu&Xl!=Q--CgzleVWN!)~93EmY@&iaz zf?!j~EyZW~#h{+FGmh&ssofVwmsx5&gg3B3k4>jZp%#+>$Kvr!?T+skht{r$$@?d3 zYir9&))S2CSP2=@fjM+=mSee3Qi*sU&Nn#W9>Z4{-tx?OuD;UvVxRM(2SB6}m9Zmt zuln=-Ml9GwI>I7>I>nxXM{SYZXBtg>`xE7wmsDdX77dpg0!QcJWhd+RINPss} zmp>YNEY~*CcRiZ8400EpUqQe8tS=lGuuV zI#NiI&ooGT6prRj8Xpf~D)Ap+Z1kV(_F}4~nKTT}V>ksxB^&vCl(Rlc;!YZp=&kQk zcZ-%7NzwY1yj%>9^Dt1RgTNqiD^~?ntgjn}x%x=gGqT#PrOiJ1=ROWw4L2g@VfvZt zkjQP`@PTU-Jf!Hbq00jg9|ajl7!r4*HbVpFxQEIcCAuD&+umJXrnQ1Xmj8vyTb-wLkF2U}S1M%eCU!Ib)4@Tx*!sii}uG$d}N z44j{`eV>hJTqLf*w(h+y+D81T3J7+Ynwq1$8wLs+5iGd!<_W(6WWmZWCXuqlXuC@qUY%1srAI)n>4UVE%22Gycg zY!SUi`79tB$udmmMq^w4(^MX^9Wn07;>*8kiCvZ$q!tqEwFd?yan`CGg}Xf!)Pk0r z$~$B==x@l##Sp1-r<*tflJeBjJJV*833DQZA~^#_%-n_>{0J()#om~OkUL}C3n{MV zSi@h3mlnfNv8lo1q4~OX#vnXcSq}ne(6AcKuEu(n_;}qr2&6w?GFQ37r=at3N{DL} z(WtX2$-i-;P`ka%Lu_&_%$Uj^Epdl0owaGkOY=S|Fo82L)^|mxPIk>)`3`QJcsn;D z0fq)gCFtV?8AtLmc?ujK4;_vKja6u>?C~75J+K?7nap@8K^8dIDs?y;+Z!`6mI#{K z$4_!)KZRp|Pss8LLaBd!k;7%QBxHqsoZ_<2vO8Dt0CT|$HRx<7ub-^T8TI~pG4Xg{ z@`F*O!}}*4@VI)xnVICtPTgBmb+-DhjKmr-(8fVHK?&90PB=z>N*jYByj5-fL*V(_ zmGoU<<`s_+;9b*UOZfSZ6HRD%QBOjrG;TN(IstDEo$lGz@$gyGuHb$P zfx3>HYW+QMswf7iDq&G|8E&7AA`h(=+~3OctDd>Jxw)>E)REB__m(vH?j{;Xb$wse zQ=M5O`6ZX=8+3PS0ETp#k5<$6Ny~H?mFj!nKH)yyrcEeozIp?Gl(V%3Z>SzhUv>-q zA7M9)5c<=qwn#WnsFqJv<*qM6pKK=bZj2fuKjKg4uqdLi2E2nR=bL_WelSiZJha9- z6Q+OWkTvNPBvD54>K>ZkanvN{(|XP5z`E&*xb_Jc^*NqEZ6=cnChfVI5@ra(7Ojzq z8C-1$<(jG3X6M2%j77gayXt>w*0cC{ffZo@3|IjuDDA=TL-i{o)B+1>3b@9mmOt6j zvpBfrurQoXbHBiYP&>ifaL;6!`~GZwnGGWw>=jFA@Fw}=r=dYFY+^7}5}kdwm<&dl z-lxWTQcmTu2MWKtBQAC)M5EP)$fo|zy;!q~N@Pm4`H_a49Lmj|ea?zTgMXnI%vqa1 z>dK1DdwMDv{ivtI`sl{|0^3N*ZfDcd9!`ep)wVv|cdktbqu-ZJRjW_GWknfoa&OS= z1&YKvi@wXO-iDMT*|r7-k+{?FaiZ=@0J8DAE0*}*@ee8(7jJf=F05A7&$_=ZicRsh zOf-EzTwf|=!cDhsUZ2o%lY~4Y1w9;c-g09~I=$wPq}Jl;(l9@0np44SJ@zZr*rC+8 z1*b2cm*I}?yfKduh>S0IMv&_jLUX6(!xn=QB=lFlbRhv&f`IIG&V1Maa)QB+#k)^u zPG8b1;0oakzR)tpMlw$;zX2WbClS%S#N3M~bt4VuCWmQ5|p3 zaO_57gC=X3g~kAHPDS+bl8}w|>E}2#P|a1ZtQ)Zd==uXD@Rh~yv8y@&>EzWC7uHMe z=Um9#gcz^{@S3U^Tsm7jI5--?HLyKd?j36uxmi>4&fYCjx>wa?3&n0T;%+E@1{1Sh zXEFA0i0_=R;e3-!&p^0XyAFqQ(G|qGFLdHJlx5!sRu5@Jp1T#Rp~duU%~T_{-Cci^ zOm^7+5?bKhN`i2{T|g+G%m?pHO;nV4 zu_bA!N)1peeN z($FHgrfNCv1if62_y+?PcpF|{jK-yZ^a^JozSUy|&Cbtcj|OY~xHoq%lDa$qeI%I= zIt}A_K|peYQJ${wu4D$UU6%wwVP(?Hdr*nhkI)t|>Tbe+@YP)CrcA+&>MIzvW15ZH z!gpdaNNrj*HW3@$k;3Qu`~iJ00-P)-SK^aw+WX?@<38FJF3CKx42mRD)YE%Eki=mo zdXY1e0S?ZO0GDB(HW-t_IC{0E@Yd8^!l8RRSbR3Cd_qBvBXqKD_gA`1ruw?o?1#-R zhf5Domu9~l4_9ll=KQ)(eHxem1k$EDubxN{d9mranL08|xfB=U#J zzbGB-?&|>{gxkG3<=^%OIt0j9Is;Ud(GlS>wo<1Bu)Iy;TanalKTM!a61l?SU*jhZ z^L!SCtdoM=($jW^ebDM0$4!`l-GKf9QeJGBwOp8R_sD=3us4GAzFRmlRkE=jJFoJ6 z9?|=Lq9k@M2lPI#=m?)cwSYZLq}QhD>j^V>mSfSt_@~0qqK{(t`D`-umA$V0#`T?e zJ)>&HTHN-NKZuaWR+W0-eZeVHNC+oNxAS=Htff0mjgEGL$`8}5E43ROAN-EEDk=$R z@tpuLr2HPgief|)W04Xf)wXX4oq@yT!{dTMW(d&0yaU-`k-(z`y5rt>b z+?2YUCP4<}L&#^EV0Nobv^9?QcVc00_6-e+dRB4bzP#INb4JUv0Tnq7JzAqSs@hnR}{9(F4uGgLky>1qk*NmjkyU-kVfoGb4xe_t&GV?>)HJ8wkal; z1e~@R44PHaKKCtN<^$UkWZSBcb!Ht=O6mC6JZZcQCcVtfk*x3KUmqY0_hHk={xl>G z!=@Max;jlzn+m5~XtKaO-CY>az-reChk-L-a{fB3g9Zcp=M#oFcYP3mGk23D;B{-I zc!xLuH=-V};l0=9Q_*4UI0wLQ)wK1H5Pkp(P|2oivYJV@Rz#f= za7q_h5Y`#o@!_++!LnZb5;i4*-}uSrPAZ1_RqWk?=g+~Igf|m~VsV8k=qt_R?wTDK zIa`$7A!8W6F#Q(HPw*c?NMU||42&T|0S=@Ght-xJ=u*FGQ0MNcLJ%c^%D|In6V;kde>6;#afRLoxbu3T}0 zt;4av-u}M03WlmXyR6JX3r6|wgHdO=lx~A_4k5P#qVS{;?OiAaWoS9+nQB>rw8o^( ze7!mzGMX?lNgRyUbCs$!qo?Zw1ce$cgqPRX-|v_-s)IulhBZ%T zD%~(o(Qet-F(}sl!kBdzK_p2=lA`$FE?Hn ztTpdB#~fqKdz#SWefR|Kj=)#XS*bI8@vvN&tLYZ~%MC#QwB0oGlK#a%2LiQ>*YCAH z|M+2Y;jfb~=|>Qk>njk7t?$uyv2k>k?g0T=mdOm&;iKZZd zGlMvLEw0cUP#q?>J9D^>(Z1X2kY|#|gg*8%4O7 z{UpXf24XoxVb{BPG0{Vf-PYiIA~ysD(U}Zt{0vTu<*;`5xbC!sDRTVI{K2YALMn}? zex64-OzQ!vS_$w|eb;Sm0yO$HNX?#SLb8Ae^K=gRjX6DvIn&k~#GuB#iE%SjsVWQMMGSic~}4haY*@j?eu1@|{#+W6pL zTfH)%wKHSIwJui58J#N+1k0cWI}z#_fxS)gJoolUM8jn{%m~(%wEkT84s%>f7efz&c6$Iu$hM}8uOp^8s{NGPm zLr?&1_Ehnnk>HL5wi330!m^o1WC$X1BY#hRDR6lG!|cncO$LlfMlx>)=*uwDU;i~@OgB}(n#p>}Y@?dWI_&6iw0+W&mJPkKeY zNMhOPpx>M3h{yYo>S3{|{xeNfiuXcfDkhm2lAHJABIo{SOKKW89Qp}^LN2rJY`yP8 zu6$}{P6WOrzc%hdl@q>b7`ANM)7^=x#X=794X+#N$PF2=vZJG5Mj^lGzS_ys+^fi@ z***6CM+(65manHJ$M3U7N~5S`8fP_Jr1=3bQJ@4m7{US%>$F>V;@=Ys+&p%+=FN3} z7@%q_;jua$XCP_=ZY}cNanx+)$x_@1=O1;kXW`IY7$ruvgY)zC1>Nvs`y|9MtJ3r* z@bi;P#&nq}6N6Yn$(3FSfw1!#eF7W_Vavenc=-?@#+3BElU)d5nUcvw{r)G8|C7il zzy=vP2u$FYe~%SVaO|jI3&1i}Ne@krw7dA0>cMJhPf`OTMzZnbI8}x%wwKB+RG6as zegO=>I+gQU96K1}{iqk|skxcAqEkGZnzyJfe^v{*()?%)p`m>bnN)y_B z)M!?36qWETl1h!I8|zahJj4vR8KX)Gyq9>E8%4C2?!z`(UuoJ$TYxiFq^mvM3$-Uo zX0?$q9Zpdj2<&BjPBuw1$i@FYl`>?%0bAR#g2v?CiJ6feNY$;^@;+>MEhNK6l-Mx5 zYm(;MYw}3!mEv3Iu&-}6oLY&7obXFz#OP*$cK;8+_2Z#f+%PhPf}>P&Jv z@xJ2yNSMWspU#87x3zd(@k}dJ)?wLQh6tkhXlwYcGLI^Vui! zmY%d;G#Lp^PiYq7=0++rjmsNAfm4d35;1=HBsR9*Q;}B_8$v%|s%ZQR?r){~Z@ogz zM-UJI0)wCH_5XY!Cn|tOcGk}zj5fPnDEQ$Z@c|i~6YGZ^+jfExp~?Zby!lO7v6tXI zmYi>UpJo;rvISt>0qx;J33zt)9Vk9W98#Hg<=9=~`#tSo~13&=9kR#;(O^Sw>nn zQzsJLAs(L<)kCG>7eh?h?`)|w>iOuTI{0mwWof((%4&vaRuvLN{NB5e*Eoa8(jUd5 zrm=cjrOdRn_&dyZic6dbUm>V#4=S@#`%f`tq~_?)a~) z-X<3D87OXUB2K->8GxQ<1ADPOm~*z_INdXs>DDd;-91j_zPvvBsHxWAxM#KzPrteK zdnMBiNPrP@M=U^){7INSCIA4{F^~dT`?R&sMHCv2JNNZQyC{!Di(zT@wG)p;6hI-p=DPfao#4=4hPB9(M}5hkNX zO82*6jB?O^$IZouPrnSZu)AVA@Y(J|@YpS-zB3!= zpP1T*KbLCteP}cbFoDb~gq8MwhP&2wVv_os`NDLug}bXxGJtJMydFl~|6*IeQ;gBj z*4RZsOc8vdx=@9AKtl+}M!NJ5}-NN2>T=3uy&FBQ-Xw`hrp zeLwH?3DZ7~Yf_nlEN6;x9=-0Qus;R}6sa9?(cpmFR4`BBfU1uq+zxC$234{u#=e5V z?eV1tPPd745)}l_O1N$0BxIIY_33IK_q~xqrbtLpiNXDBd6i+Odx2sW#cvdE@rs`c zkExG9SAa=rqazhZ6E`Q?go>Zi;`*2pLoO|bfKKs&n+SbAq3u=q%eCrRf$33l*(4RK zyme#Tw$mKA>QOB(y|Sk)r(OC|8}ZVkqT#k`Y5C#8o?`QqC+1m!s{(Qg#HI$6qk^_oy2HcyeNS>s8i z%GEyf4NH!LfH>_XxNbuyZ${9*1Hbe_>w`0O*DZry){YbdGaV=b7`%PBbyBG`p>O2D zxxH)6Ww%`p-L@c~rNf&Qs4B{5G~ z@^ydgFXeq%9_YR_-wxyqhe-29&S?Z3ht<4j5MoBUmLgEqd^>wYl|lF{tvN-&=AI^xye`Us|k zxydAyN|Uy=8Q=Fvre3uapvp(edP`aVS!XB^$&Qc^79o@JC-$2IrBK}UWK<3y%;Va& zW%2XXqX^IM+cG+1Md)NE8n$KeCi0bYH*scYpY*cD1cAj@zLbf;*}z4tp#bn%aY!Z) zxQ*$hl_UtbKXzP1lh^S6+~0cp=c~H^c&42+%Xf&oC&I zekZXC2Lw^BrlGc~6zWKt%+-6m21+&s&)ig1(~VWTr`r|j-rdIvhWI__b=Ci*+B2E@Y5m)y84%#$jjIr}Zkc(d9V6pba0eT5zKX zm7#v>Kv58pYC@4Np~oQPs{n^bDMP_lGZAG2Au`l7pKiobrCgOT%hBNZXN2#KlM6>y zzMpLq67o4UZ#4+4NGDh+f98-@Eb^^>%trow|KMWyd%t;BlZHk#1YPw?9DVpacC!gz zrOEXyo3-ExAi`bPqJ12tVBZ4RvEv;GMk6u!>%Vj($ z8&^FvtL;!=67f-9(l%~JGxLfT@}5$ee$iTimt2eFXFaB~CwK*|GR zz1|%$$f4PCdyrmEwFx!u%{hRUE$2`Us4=wTN4|gmVNJYh25i#WA0OCZ{KNvlIcgl{ zB=->nTkT>r-!qqwR_&H6X}n4bozqsK*z{5v^p{(I>>Gk!6OFIXs*m2gU3~gR0)m{x zRodPbC$mo^j%7_rx%GNE4-$bClQNZ?C~L?g-{|ZDt0w-`+l{utoV!J_zXTuEkLtk8 zcJ(ReY5m^cpAG0OhjV3k%WDxk58kRDeFJAOzazx7s%!A`P<3sY zj-*6eT`zs#5t3%NLSQ#w?{6ECxVP#*sBD4nlb;$9DkGTrV)oc)d-;Aeg3DS^-ALp? ztT@zFVXG)j>5?3(pT=dWzrL5o53H_&a#Ak@DD<|)c zygmoCc;2C>uzDH?a2qn5$}1g5 zqng<_krTALlmCq}U$ioZ+4JP_MF)-N=RKeM^^d_-+b=!6?7y@O_O8EmaI2T%!uEB$ zk->&73;1JQf$H0wgani5m9db^hV9#(uhYX9XKr!!BPy1o=N-V>x)x1XAo|XjBk(-U zYB$-7)Oy_A59?;661<#k)_dk#9AV3bH?b&dM6t4E-cDqCK0{~&Lcg^R#0g-z!KN6F zhd;ezV#0)L!3vkN0==(n67!TRDMm(r$?d!uwlCBK=5Tu`StZv5*&2J#6h`BKtu+uV z?t6iDeSJn&?g}M)f2= z1NOT8D@B>a;>gL1N5AD(AKOZ|<@%D8yQ&`5Z6W1pROHgGg4V}OzZZ|A5NBf;T$ip? zQGqn3{r0slbn4FzjVZKM)0p5VFjMI7jCmZcOgOKlzP)%F^@EB}a zb{NjYsiCm&SBNx-&2*YBiAk?kkvMA3e*K0`a{Q+Sr|oi6#`W1o;m#=s5sZ2|M40S$ zYXFBvy#ce?^CkxG{+bN=4I59@X0QY5^Vf5*hb_$>*{e>CuCJ$u-K@$R#inSK-cJ8C zSKjA0`0<6R(YZR*Oj6Ud=b%Odsb}ZV=bkMXI}If>%SE>_J-((zgDW#0%1bT!*6@s0 zW4C+cJaji~AdZx)otBwrL%aWdmFMT8_xwb*hA@L)CK+3W27ucld4#OB@;@6(C7!m5 z;)WhG7Ttbnfmc*9S#sTjB7 z9e3T@EN>5vvE6r{Mq>^sE(B(c(Id3QeujJtOv)*hJuwO^}B@1}u~CsEyrYI%x0_yG>6v?KQ-} zhA9xK@dt))92-*Psl$JGLSYd0+7AMS_6vDBP?*V8(!;PW6zD=G$yz#|;0)q5&;8-c zf?LJ%NIqjQk-HlV7?cKJWdRUZsX!%PNWe&17kEoKuJ#*y^k!9Jpy>)X7Wa!k#YG2y zinTwF*=oQtVY53PPbyjyoqQNV0Wwp_goh9Y?o>aiF6I29Vi z0KEoOeEn8$(X);284rd}17*OP%1j#7!tu@gi4M_S)ABJqi1F+aqBoFu>2$!l%=TuP zLE1(eue=##zB9*-?R03@+Vu0~%BKsS)R$RghcbK4q&2V2;~L!66nCj@&6@9YjKUc# zKCX)*4qPSn8y%g+?ls(3pnBFJ{U`ok48@0uqs)Y~blkC{Y1Ic;(m(%m7$zMt`;R=$ z!Wu>C*`eeQ8Nk+Ag<+lg&5La7J<+uBSQi1~<~KyysNqo^ojZ-TFULY1L`IgyBe4ts zpI=t`xtkJHroDp^+bbji&pU9(1%FF3Eef&q7mE>TPA(TrBGtmol~UK_>Z;NW1kbH(fB)43;dD9m53!3bZwZWEgAm=K^U~Sp!tr ziB)5Zl^=?eBSqGzaIO+^sQumoXuO%ie5uDeeC6&IkXC`&Yq^QA?L|=qw+!q67vzf!o8~}Kx zOu*`**m8ekzO_;~=?dsl79<@L#RIlg)(2`Dpa~&+Wgj4@-_BL^>y4!Hr%T06KOI5S zArN@&*ew@~BZrJ^VD8Guo1sXdqzDO77Q`lP^^VDW9S#6uct`xM!RTh;@@4~HR_YPz zZgtE;8J<#Osnk>uF%M>dZK2}fOmUcNC={#v4jJ;gwhe~|(jn;NnGZoIg_%0=v?Bxe z%gd*^>1Lx}zs6(7IdTNb3ZT8GJ{aCar&R^#R3c(iP2Eg7stwf724Qj zin;Orq79{Vt5^-A_bI;);~v~;CkVP8U?UTF<3YIoS`UR5pn?IH1VdT%l8WAKEI)(g zfUq}ea5&KGhlQ&Xc>N{su1E|RMe@1d+^LykL3x|J|oQ+LhEtUXo%49QID9dDmO zad#y8gz=qk;1}O!1WZ~TiDQjvK;GS-DD?^6KUr>;W-U;QUSlyG$zV2i;s*yxn3)KC zO~hH@^O9KMyG#E5qE9D8;4*-kD!wegn9vM%byM^Y&!@7$+@eIf zQ#pJ(E1tbRY`#b9=3~vozC#NZwKtkm2mMi9yuLr?$zUX+UzzOi_Eb==0|)0*+s|WS za@&O484DW$o#Y)VSo`v;Cb+F8zzhk_faEK2n-Hu?2;ufHYs2Ww9J~R`Q;M8&u1xeN zY79vT2 zU7RJx_xU{_V)89nZ3c18vDkn%Q7QHthrN-qB-*h7YzZIEa577BPXqxib%m?v?Vx5X zgD#hwH*l@0#l5odo_>?#8!T$A$@Z$HEO*gxvIL!Skc{grA#RX#D~Hd$T5y|ZNR9rt z{Kc$|OdQn!z9t)+*HUOf#oliFBKqrBU~h_qr?Ziqc339pw*|-Lc7kXgV6ARAwM#W< z+n@)?lsZYzBCOZVsOvvORd5yDwP>&6@!>&X)!8G%?d9(*EB{Wd^|DX`(Ph^C2qIpX zo1eu}n(IHEB3@?25wD8C6{wboT%D}sy8reJKMr>RfJK3RX^EA+281*vPumRfFL?g1 zoG0*(;zuxH47t3Z$JL3t~j5>R>(dC-K~utZ+RYk(k#h?xcJ9s%O7iTa_t;*sgZ zdR7QKDbMXp3YQytu|~O2s9ho(grvdoNGt*>>cO!?4xGw0fMCy0yL#=o^T)bBnkBai zWuKg_@Vz)FrLt5&T~%CnZa*{|A)qLA^zc&;jH4r z_X>V|IhS(x*TgqWs(WX9RL?p1%Ir8-caaRGzEFiYOmeEw(@vn@2}l>XporMJ+?(iX zWS2{0;}wDFjU>#TruT_o%W@VO0ROV3$Pm^SsBZ?>zc{=tvPJnBrZ- z#cKq2h>?TwliW1l0zAEM#9O}bcm_?<1%9(rREtrC+5tDX4Usc!bi3U8vZ)dJ-Rts? zG$DZLOQ}~bHUINefdwwluy|V>fSP2BmP)O6N87)|zB5;vr=kn$3Cpc?_gPy6wmw>I zwNI}kSl~Eutzfa1iVjb|Qpe#eW|@kr&W~52KJ^TUG2{d5-_x9uq{cUk;NuF z=jAZ3_;h)=r`$kOc^NBf=`JHx!cM+guPTlpO|8{77lkYtV%jpOcE)30 zLKw!Lg{Q$?MdtZQ3g(=1(#7}BN3{tkkO1Ku6E;+9Ge^hHVpKo}doY^+?IS2_nhBxq zT!%w#&;`=n)Em~Xc^^k%tySH+186Jua0qRaQUSel0V?w~&@Gpon#P9R_K_2WX4gl5 z=1+qX{hmc;_&wioK08cgL&fRM>rkLOS_Y0-U6-s%z)|j zo%l=b1O`l6XDh7rYM-aLc=Wk*p;Bw0-!R}9st(?K^aIyqLF7Gyn(^Q?vDfD|Bcpr4W>5uN!#@jfRFNa%df z%J(qTgJ`f+#t%uDev-V28k^a7`aSkMy{YckaVRU~T<$ygUbpKyMrF8)t%_%tBH1ji z3hgRZM+3@;P1kR<9zQx~_MLy%x)cp<<)Es2VqWa=R7{EVeQS#9Ysdj8Dv6{3WlGHq z{+Fh;V}tD_845TNr> zl9icW+1wT@i_aAlb2}?(4H>;eDblYkne9G9#A471zAQ06S zY$$AgQ(+t{qXAl|^l8OoH}8N;;x=V79!~krW;I_FNSkIT90-_x2B>XYJgYpn^re`b z&`x9;yBn3aXjF^l$LhsvORBsU*l4t>sD|{bH0b&1=~DqJ>$}r`v&IYl~(zwLY4S6 zZs(&Mm3(DsA6Nb~9yg)57DmR(VxZ})*!g9shBlDEkd4-Hi^KisZBT+LDiVP=Rn#Q0 z$pL%JhGQX#a=4N{9Somvh(f?Ag@A7KjftMf^lZU`VNm~v?;$z_t;)f0|ART*{yukq_vBpXth~R%+Vs*!*x4x7W;X{mb28_71w}r~yflgx?~L!{OxF~X zr`5dGbvF0ttex4%zBtPiqivM=w6-vtJ!9FOm)3aK1oCZhqOSopAy4Pc(#8IuW@Y~3 z)k+YkL8!?E`3;Xm;047OD*~k98*tr%&TNIK0~bK=c86ey115>{&~4ArF;ZUG5+0n- z;&|7SS<*O+{T}o_`ai7_Z`)VWDdccVwfaj`8&M(%`1MLpILZMF|1g4@Ftz1eY_|Tn zPRc0-@FF%GmiS3v8=oTN_^-uq(mb^1 zG0Lp7bLn!k6Jw%Sb@^5{*KPv$YR|Poqc7h*v?7+?#+|)cZ5JEN5ePaN)Mzq8tN#_= zt#3J9tnOl$!um0=>@j;m)bV`MT%}xzy!Qio_5X1TJzH8hz-3d(K)-;G<{NYxS%x(tM(!2z?8Z@thE7m6TV z3Q3@=&P%MdT~R7u-3j#j@@hgp0#927g;|siCJh4F8lj~9&Sa0STB@mB%p_h@G|umF z%ww)77J*9W%|M6Ql+hO2`bbfXt5)7$Z8@S>ma2BY)y&+#7bho>Jo zL&*b|^HBg$esYmd`%hQp(=wFhBCC|1tF>9{d? zUffpS)2DKCf1WfuFHvU{X>D{qmRYE^{Wi@pM?g7C$e(%8S+u?qi;)(jG=12T|2h;t zDFK*+3=sUDYmYDgZK0+nxQBc3<;$1-Wjgf^14}1o#?_%r3pT;#i3mJ+MBM7jHn$yg?A#TbnhDz~?= zsjgQ)D1U3mSc7xKZtGe-{SBCsI?S_RQSIJ8d!c6Gg&qF!LJ`NHDd>f#mM?5q9rZUZ zRNeI{y1%3Q!a3Y$i}Y5#*>Fg1`fca-8*X_tZt^%et;BPLwS?Sl%hw;x(Ex9z0k5Af zx3fZN8n4P&f)Xj?DISS4%f&hRic$wO475_&pD=ag%&B_#GMU}SoAqf=Irk^OZi8d& z2Tf+yw}e+DWdMBn;5>+HB)B!cMLT$m%V^|rbxc4mllYa{c-YFBPZ`0h%fD`iQE#+O z@Jqf>cW6!w$)YHN3@&>lo0Wzv)9<~F%w~bg)HvVl3$zmfZ-Dchqt}yoLmPkn zdqNJy2g4aQ!a|@89{j=LnoPIJ&ac8`Nb2BmF0aOQE{6QW=PtW*Oz!vTd>#y49&)9G zOXdgh^s(&veDw%{G3C;^k)JbM0MHPOW2&|9?sy=zP-~q9!13{W(Xb(g9AI+w^3M?d z{&X|O19f;u$mi(_leGXxG>UMEYL_3X z+Q1KW;&P7H@@Lj!g0+@v!*+B27`5wrTV3(+VR#Ljnk);pl-Zw$9Sh!Jo(sddhEjzH;JjCLd- z2CX5c9jV+d{r0Zcv-Y7Fl#y27&fmMO!zFQk4CLW;Ig9D@sEr{M??nZ~6orhQlLJ89 zj?Pu?IC^on^~3rviq=i${MFaSeX$JIb`7f(G&f%~(6Cd!I#lXNtB1Bp4LbT$*+7YL;q+vdI^$k%kO!IqHcsW&gVpFP6PM#4E!Mr9>-T$&CoNg5 z2keQdBPv41_IsyjWP3pkPO{{}bz$gbQ$~(BM|?>H?Qk+f;tMr4*_}Zsiryqvf6PaT zMQBloxFoC>s-oBC@AQKM&`^C_L%_bFq=LXPN#XEL0h~T$@VWO$EwXgrjUoEkGlt(@ zw-2UA*Sl+-liLZ?%*QzI)t&aHb#HG7%m(um9rq_C-2ef*%l9=40#BV!I^QeLoWbu- z+@7tTH%f~TpXifmovsk&Txzw$SqpQggUOtOnNnpdv>G*@i(I*Hfy+(az}*TSB*9NzN_t8d2J>LP1 z_z!KEbhTmRpM@-0yT_*GzjpxyI;^RYtnQCBCm*_3ZV%<#KJlv{-RsO2Y>k}X&(v7w zTe>V=kn!V0;=T8mOXDHgI1h1IiSsE{x^TkA7H~$8CRPpDHK;%((%5fsx{0`cXh%IfCvJoPP5D*;eHdrr=fHmWT}4jqz-G@0=~ncIOi^mGhGy1bOlyjZt4J6Z|QWl(sR-?g+Yv{iBDU{F7v9lTP@Y|<~HU1P1D zY3IoNT)59&WJMuZKLHL+`aPX(PK@k*U~V0N;FZ3K@%M2ix60pIPFav6igRNqOeau} zr1o>N3o~RJ`6Xa#@8MB&>$Y1K#a^!}llx(sn-7eM!aYTzhJ#jz&|#&v$I4+e`2HQk?1pg$yv6~v|vIfsPdYT<|_wIoU~pnx?49(Je=V( zGqm~{xcfPtTLZ*4A^?hK*8oi;KA-54ZMH;s1F`_85D{!}n+-6$;f#+67_MK4Y6HgJ ztND5*F6_p``R3#T4fBYuxZCiW`6v*h5HlN*)9V^NWjzhb?|dIkf?uAkr|W-#H~9Y_ zqq5c1bQh!Ua7iLQZx!vgvKsG~>rG43R8f}us>iQZzO5+pe`g5I&E@gNTGL7x35I8q zKB-sjGLpo;D!Zea&z;1g)Ig1;Qp`kMhXR&9jFZulx~s>>(1ch|)dH353?qBylnn$r z&8A?nh_{kFX_?@I&pd=!Gh&MvaqwGGxQt>aZ|IaZnFtH#d88VQUt+fvs27uFIUg>P z)n=X41CdFZv0EK-y(c-E4kY7#GVP3PCu zCxGerU=ofyZp(qwFF;151vA_7CFnAZHFk5j%8rG(TC_Z;D?V>7DSQ2y-)g)%nrT$? zlm|qSl&XrZy=%hZNGP3_sWgm6HsZw5osOeM=fWvVDEr%A)-o~gsCj)J zWvnTKtY@nb95SSa%G0{Tu*ZL`b#7J1j6gdY64o`$W{bt;w^RsggDrD|F*$vEX|&;h zeQD^v#hT4hh;QpXZ**|)T{^5)(;#;U89!Z`-Q8sqIlSKvrLjr}+Rul-VToyV6<sznBX_pp^z>LP=m`VG%P`(e7!r4>TPPcFZVFiR4zT9lo6g4 zV)Tt%S_%L*swYQ0LBN|lpjOUNiCNnf0G3ZQpT8|C;s3VIxMV?dlaJVOEn|8Vwx!u# z)2U)(3}*-_Gez`vaf>^`Iz!{tNf!Zpn)J%NvX^l(d)$O-JSxx_DZ_8~W_ zWxIE*YN2s+5mz3`;m42%mcuB!p8hdimiLX4hqZcz1rW zo0~oCl%6P}bR#%M=J$h94l@*Go_k7oB;JSeu~Z}k9G+c=!>7k_en#z7PpgECX}>df z{cp}gMPK-R(79(S&>b~*{_=G+AHi{NF~m6xDj1gyvZ_$7#fos?h0WQ{B2)s^r1tyh zr{z3wl8N-XqHHuB#!$#gr5PEPG{1eMI26VE?d$7+wyK-R?|ChM-Cazp^b?GX#~d(j z`U^F)oZWWuhjVKUS{PP(p1oqGtJ2O&!)RyFYqPkrQ-vP}Fj^H>^?0R&jH-pI*=HD( z`D@#*u{-aT&9g)=GFf&QcSToFr!$%kCdVKwJk)@{b|{T|h6#5Eg}7}xI56}q$H`N- z@#;`ABKZTWJ7WruJ?zkTUh!n;XE5Xgj}87y?O7cXI*(1j#FLqxDCn!Q1{Q_ zGPwxKEvfGIfWxZ6*;NelEOR1RVwRj2EE+RTC~GvW+M}qIq#r?;A?EwT;Uy210lQoJ z_ue(GYeIM|T$lByS5Lol0DHJq6G%2s4dg7L;U!PZ_Vj*+8p1myYkS}rS(1K-5p7Ks z%b%Wh8g>9YNGiZJ63z^656##xEzyTMX^3`poYC3b6ich$=v>#<;owkde2ovY&*SKZ z)%Xwnyh$xprYSBOYe@5+@h!iPq$zdiL|Jw;%)?#CiMR6`Eco)@Wzipd0uSojRF=TC z$bMJ@@sa~p^W)bIe|D$BlGrS5F6$L&OO(#Henl%sF1+O9BEi=FHZ}|m6=lF?qfujy zYsw(N30a{Qi{pdWL){9Cb) zeX9nsIn|&OlZ}dPfN$e4^d5=hH0lxXVo#wqZ}0f?dEF@jK4IZ5lD0FrpLvuTcHPB_ zGdbpPnhkbm)XRchPwnQjlscz^F6j6943FaoL!0^6qbgb4hSA^c=1mPc|G*^#f5AWn zZZ*%fDFYp%!x_lg$&SLI+R*^b7U$HKz{h_$%(f$hJjPPFS!ItJ+59m5QrqTMc}hLq z%)-)=u>{+vqyEAmi7UbqoKJ^cgP(dT#QK?*&nUF-2UY0oz5B7*o5xP1NXc;>@c=Zb z1LxY_o51K7%Vwv2Yq6jfZ1I=}*4QhMdP-dmjV&32^!G&ztro zsYbA0o<6Kk7i&9iRWR}bPy{fO$k(55qV+lkN=`XEp6&H-4LCk7YTjP%u^9jQD###4 z0}xU&EVk`JyfC5u;uc>Jg7Pdx`$H#vUAct?(EM>71U< zkNB_y0U)c*Q$rz8yaZyK>svk4kEi3^VX*>-!CF5QNXl7kw^8GGJ#J%{n|&z9-^IEi zW1MO<9v;w^X0$$el)I8+#9^qprtx}U-?K-{-OIY>&pAROUj%?;Oku){B~y4k0@L_C z!?|;ygq;&7V~V5fTErqhH6esN3|%ak~V= zzbVyk&P*uP3w7(J?b7LO%;fjJml#wn?_RuI(dqaa>-qj;Plpj1B_6Al@%DVRrK9eB zSUNEuz)^f}8A#K$jgDUPicKE5m{flMs@xbJn+iWU$`$1eFnB?L70-u=!yxmb3zn$6 zJDBi`QnnnuXc2(GFh*_&Kl`Qr36dp00u;q=uiXaRboEcDj9mjHA`|l-q~bhS{^rL6 z%7*ztcUZEM(QLAKG-{b}K&SZmMM&8rMeMCTzYZ@UT6mB=LUHIH!$ zEm+nZwmIPO`&3GVuMizlYfRO^dtVWs0uzO9C!Z|Inigs~Pc-i7exI~H^?R5So(=cK zW2_3aDZw6d;Z!)Gdy8$InCdmT$^oA0jPUij_iANWqS9_8`dz4YIrXEn9ui%b^Um4x zg+qS|C_gZxO}#W`@FYJjzt{OS;?}cFP;I@jBjin?k_Nf)_-N|Eu*t@U79W3o_vXQ~j^+&M>aasb`U=Kb>NtTr?e^U}BZk3u-Uk~e6KgtOd@F3iwF|u{ zrUD1jsH92^U=qfbze{{9(6O!?J4fBcgyR8#Xy}2jn6Iz$v*1O|2*HE@NAR+dB<_+f zz_=XOvu4gs8xe$Y{4=G>^>j%jv%;6Ci6Wvsa}<9EWaTGP4qjW?l8QCLr)3t z^Z)MwQ)R~29L+8}ipiELTsvHY-h}?JnhTBloFI(S>U2Ocm9P1&S!t8SWYDZ$LhmJ4_oyoU(G9p;FY@xmPisdZ)VNX?&J}Fvdc4&apTM{3sH4GJO-Bh+)=(V7) zDlH?G;M#;l#2Mr2qStM$Q5$*t`-n_lK835eHu3Y?{mloPLtM@)0v!8!qC9ULHToK> z<##(|X$h-urF}(Jc}7Y#9@D$=vPJFJyGWLYTJ#=nnI*pCi-o@>FQp$*?2p{xA+lO* z>fZJIxtJUKxmuh&eOO4+_)WFf4g)pYbdL7J)k=p{|0=2jX_PF{SPRS-$IJ>hhwafW zgpF!V)mEFU!ADMZ8F4CP~0EFvzc0$+XREG@AI1I!~kN@QU==ANdOna!1O+k$ezuB=>Hiy z_xmLvaQAs{_i;XpetP=s@j#sG>YPT`^MY~7r?fSAW$eDFWJM6Mrt3YrV&t_ZwY+~( zECt2jlC~FtBA_(*N(pGzmB5{5+SlY<3IvzAn#wvi%{~C`f$vk+tE% z_OVp4itQIOvU)d%>)hejx{P3-&9~8Hfd^Zr?={BXNnZA>Ws*zhe=W<*;!s|PHoBZB z4Oythed>r&W{@JMgPbPrEE!^%a!eyVsd4CHmkXZ`BrvKPD%coW8vuG$EUBF%32aW! z0G6R@zF>1h1tm{<9F=B_QE#L$;AB^V&-A+co!isC{-);g(yP9L`5_z-vt%?=(_ie* z{8sCo?dX=yvx_EWCh$?goZfM*9aw2_%+`kz;|$xwT`#NUs>#+vSZe+0qdXIMU-6>G z*V%w+zaP$OtzN!i$=3gl@9GH$2ltCX*~jm^LcY7oblt5fDQEH^K|S8nl5G1?Q`SXiI^?bWcM# zK3rG(h`R1xsf4%uRq!Ym{dQj!2AX=lC(sxlV#e~?P>|f-M#ey3aQ_qjB5*LqYg~|4 zVEc+R|KsJiD*sEsifl1nhjydaL{+#2fBLak{wrjV(-$XurbJPf;jQg-6Z}JI)bKiT zZ#9Nm6AA$j6+H>PZj1kVZ`4TpIK5uo*Pd`f@`vOat8Ana1ALm-_+v>cU%+gZTKt0nbViAN{)7_bo z1wxZKbdx*GuU->~0oK~DZnf5PLcAW13EskEK}cOe-EdW~WjaCzte#yG)J^NK)f;6d z#q%HB4>hU@fd~~t#vkv7>|}HJi++5b&bi?6`4irsKuRQ?G-dc+E>nkz%@g zPP^-1OkhcH6bYd;f31}yug??FtFbT~#yp)prSTCWKEB`Pr)7rcDeyJjVY^*nKBanO zq9GPSu7`34?M-eUyi;r#-Y}V=KFpp{RwF;lIpta6-&*TTzU9g$to1LpQRYJp>V7k} zDzy7UsVpY*F8>^91H)qJl9pP$4Nlp>!0;YI|73qaZ!9Rh_g$2%GtU(=2B{`vso8nT z$%>V=&E7b9)k&M+o1SUj7ksaN)tKSH1LJL!C-c?Wc8vfB_rZMs!}m0PnFrZCgjJZo zlI!1VHSp0!TXJXfB))ZvIO?M5w)91YfW@Z?v>H)g{T(FzXMWZVe2ORH%|3?ECer$B zK;dZ?mj^<6@Y#5vnfMj_uX-i~i$)#JoGXc@*-F-LGGOr3(kwi)vXY@~dlLPWaJ6l~ zl-hGlS{hu;!N%`Cu|5p$P>v{B{iMi_4rT z))jtndzFxD%BX`HHs@r7L;jecM!yGmgFdg_R`HwuS`F$5RRT=r*-z=R$=P5T$q{iq zB>e){_isKpUfZ3QXh-Ss_>_d&xFeK{T%`NNpY^|5sXX5v4{_9pRW5S1Cl3w9Vt7|< zkBr9?;EDG^q4Q#MQuEzM7=XQd3Sr=A7dM)B6HfH!4?yY8*!NR2RuH zLZg78us-Om)fn_H$7!(#5E>)|-)g_GnEV;ShUZNS1_sVlv_KyV^@AecA}cCgmFSx7 zL=wc(vTLu5hm>(B&J3rTT^%o})JtIj3SGtE)%6%z0V&;3ISbpiFurBRLotv0wE`ks zy-v;H&uWn#Lpwl?n02kEF5-2Y$*0HXH$TTL(9mSBrEWHiPB1zulwa{Kz$z2;xfisY zF3LHatDK-QB#B-E+6nXPvW)R0Ol`?e2Qs~KX)*l1Wd=0>7RbK-a|jL7D9Z*pk1E!e z0<+~?%O5E-(&aJteKsH=K(2YdicKs;CCA_sNYxQMI+#0l-WvEYNhl14gfem<7RqZG^to z;M0NNEFF<)0!3qOrQ>h%jJxyPBw&oEW5|JlpZ*JL-$nZw`lg5|H1e0(A>WdiyQG9y zx@G05KT;suqDlN`G+Yfs0lTD9HJfXB*?o(E(=&L!#+>5L5+9E23xXk2jl!XS&&ZUa{OwX!snu=WiyVA zJFfvbvL&aY3Vt4G2{VFlVbSi3n9NtKx!Az=z;SWASmgq?@BYB_M%TW)vfkdiR}Icb zNoD9$UmtNfByyIT9VnfS&XX_GIei4RLM`txw9^^|9JYtE7+Rg;J5)vKIPC9TllW~J zfchRf3rm`^0WM>$K^G1C_41zcBSjpwI>TU302@2i_lO9_$VwHETDB3qd3B-Wgvn&1 zt$ucrLX)^;ch(D{YVB+}D&=(feyK>e_yZft25lR)>j| zV$b}eSW=~9I22dzHZPDkZFi{?@fkkK#~+5n&%sm@$>V4|+tKr*-Om}_vBdc|yuexR zGbi9Uv}IcLA1&RQbWdA8>8p?oPkceUPpnHqMut3Ekx)zLP=xl#sDW){b{+)StXyoe z>!_%&%KMAcOL%PO`bSuG=cB!mq$%G${KrZ!n|(c*(MJ{EBul(btJQOtIFCH0vxW zvwXt1-`8rg`!khX@N75yM5sP(=?T@|j6aO4R`F;Kvsl&dz68B;7hX7x3i}o-??vZ3 z{kY$A(B=Bf8s#&yR^>A!E{_e8SRVbiW#Jt5!)tOg882c&-`Jj_=pP!tE%G$@NSCQL z^Q1rYjz686^k*I;+ml;;K49{L?(6me=&Aaoj#TTsbKQBQfO%l;ju=v;ENG0g1pI}! zDUoWikfX^gG~-7VkTSxX8*fxB8!jKjd=DB0Vh<3Yy!Wcg1*eFpX45L`Fswh^I3gqUHPB`G9{H(Rsjqw zrz?N+;Ihj26vLiv^u@pfMU_Q2gM9V4&2QwiG^E6^{jTxD##rJiB!fBsrlz}|#aYqK z&1)6wqx9YdYrRRdl_VUCAFh|b{RVp6s| zYhEAlX?~QrnlLj8M72k{p+o9lVE)@ev7IsA91J4PS|<1F@wUYe+x*c4LBpaRsLJV+ z{H28$4HYqcLZvxupr-O{&?1-JN;$CKL^FJ!ewjlM|49)oxo+_E($en9juiBK;hNjg zQH+qs;WIDM^L5L@L5nrI;WwIVDbCMR-}KGNyB6}`^)ixC|MHXCN^MR5);FsNzu!(5 zn;F$?^zgSrj)sZMpd6-)VOJojw2o^Qn&Z=-Ow`5PGQiYhdi%X*=BaNE{+CD=UCPuu z8`BU{{<5eu16s(`qS&FFzSCnqOg*b{r|-tz(>GB%qnK0WANt_>ZJ)^cDY0__542O4l=kpA_{1 zKD1!YJk46WwoMP8kVu1*gR?c(yj1^?=WmDWrQW@=Mk$~=z!8PhSj4(3MgsGDc)S2Qx0?Mk^<`>2=^CjV^61#; zj0e^Fp{i?HZ1j$U_Z8NRqOUFe-tx>reWF=aaL+SAz&@_&r*n5_{8#j5<(S()8fAa)Xt7fx zDIN_KE7G##83?+;#UmO<%KIu%9_b@XGYxaAWRB^*X_WEIANWMX+xQY$jhYfE4x0&S zAh36lSwjw@k0HJqNGd1^JL}iDP8i5(Bu$7bWp^F@OBt1RZ{Y{+vblwscQ=&k&F}q) z5qdH)^x{KZ*~Vf3vC_UTAG_(V;Ll1U;wHR)*FcBNb1RKXg|Jf3y#qjk!}s9E9m2=K zDuo)&bue@eRnAzD7#TA)8#g1HbVUCe3i1#6FYFqs9TQ{}pP4 zQNY-sn#a;As6KBvIrlxpE(!!G`S8|L>%Y20itOSaVX2+O++iQdE*&7DS=Ouc<9FM& zSDQ3NnfGcW`j=?H=yske1K9TR*56a-aanmN6U4)uPh%Z1EU4yM1Jb=fbx>KK(_g#W zoNo(H^J`3{9_2zuLY&%x!>=#M7eU!p$k8W-L=oi?`6l`D5n>gOR+dDg-jTF;2#>{J zCqw3fNy`lJsq>;SwcLc2TB<;EqIYG~+X`8F#P`mV*Da?$rMJC`Q1vV$0t#>I&ROw0 z=0rH&!~e2}j;R;%9xVx@F*Ilv`g&cG-wDp-tz4kxEg8um26h6H0jBS3#v}+gq-@bJ z^3Khzi;s+3M_|*5CEveplgcrP`Ff)LI8qVvxYTRkfgcm@>nPb_3uoyAT zE81vzyPQ3695fb+k9=g)evaj|8|^8pZbSH6CLj@OUx;?XkSu0z=>p^TonBjJj?9rc@$5QI?KOe5EtD3HhTrDA90KenAKM`&x8_3Af$2tbP zw@~vgcuI!QFKT_if1W{6_VDq4ln7~t8(9$!FLIN3R~U zXpdMDm@@~nl@(c@sG3WKJn+7?#M2x=$RC(9ltl?q&ua4TzDGbUiT5&>$EOE08&@!E zF7N9I4uNw)z4HSJYkr}B$&iV8Qfktjb`dHvm^E+vD~MT=@;Rn~Ou^@axTg^+9-Gf+ z9#ML$;ZMS5pi!9;O)r7J5A4MNnx>PJM7h$IfR*+zT1gx@8yH)MR~b>h3`r3is``GW z!V~fUDUL3WM;UK8{->6|h$`;ff>#lINjtNG&!g!3qYCVtsTv2Vgj8wmo#(ebsHUZA zWY&#)5}CjGq$|^%bZMrT;vD^&d3S5P*ad4#0AuM5imMgTa3MssP$wi{=2#vKVK1-O zI_2E2wyd^$yxvR5E|gd8g&RYp8$>3QX0FW8X?O5$iMIi=&2wxrU|i$0Nj8*IfGcS; z+3-#wQzA7Z;gP!lbG$G_5E7}y?Vjkz8%T074&`= zC%l1AxQTH=KysO)Fj4A3ibI%JODdQwwl%{>Mmb9yoLk`Nj9r9d*eb-6oM$^ry}PrA z_L9+$D4X#x<(X}nu$>v0?ti-*d21Bq22eAR19Uo+_n(`56iICoIC0Y7`!Dq>4$uTF ztYnv(Ao9jv{RHGMrp+Zr{SSITeKx{!yKUIUxI0>OXQ^9J?5-q=&Kn(Vbl6zMrbs)d zN`)h4r(QjD@4HkIkAwmdC-iZ-*`%bgiM;I01F`TFCFEubeVM$1pdc_bK_5nQlabCI z(O6>AD|+oZRz}N{=&#mbha#LGLbkHxy;p9b6y;ul6bV{HS5$?JOVjBoA9uv_a^z3` z3c8y|1^_8#KC%ORLS0SJBGaeIfYb}7T95{)%@m$cej0W9srR8Vd^Hs8ijI{z#1Tyg zFneMktAVCZa~>BVw5{U?^lOB$$8h*>S^vo%Lpp!l;@P69NUvI)Q0kz)cJ5pU*xA zu;MeF_ra1F*ynerF{Jc73e}}7k)?4wt;VbU6*8pT`*Ow^7puO$B&olP-&7WeW|*&0 znQ>j1EBq^y@ha2%c1Y5ZS(rT7e_s&bb{S@xJ!aM{QPeWEQtAH*cAT&e(SO+wB#c)s zpVc4Rxl1!9MqGrukGQmVa9cnJ{6hWi)MRbAn1IUyKEB7(V=_-zZneWs240hp>n{-v z)~;Z-hkzJM>ZmDCF6?J2wie8N$EWVSm^l8)#gN{G8xk?3`q?#0u36SS#-7)1Bcsz) zY}#3Jt8;PZ1Ix5p0{VYw*}!PvL9I3xxy`1{gq5!Dq;*UPCNdNNcWk1I;!5hf3;w3x zKVIKK!nSLWTa!oMD(@U&p(k@HNjM|Om(ugAqAzj9j!T zY=HT2p2WTPh;Wd4WI31$)*V>n6n(QlXw!!tAC+_Y&0^rFY3P%F2IxYm92$U)X@s~t z2bes+u%PPrd9MVK3#I_7P|1gjabR*cI&U9rP`m~$$Yu#23BoiiaF!6cs=Htl^=?$B zzceKt=SMP}w_ngGp_UnbWW5-DsRUJEpGT-_ulQcK=~a9A7f%)aEQ>lwq=4=&Q>Hivu1;67 zTK%Y_f2OsA&zvP*IQ{fJgkYMGN$Zg=gd~^hrM|;{VtrOf(Xx5q+@>h}OisKaVQEzG zcrPyOw%OmZi8MBPZ>`_Q2VHk6GFVi*a?uQAj>{MB?}!`zXn{Yy|L<%Z?2uvO;XO-y z$s8+-w1|wU7qZl!nn|H21eBo5#5??N&^*T}%6!y@@1U;elkU8punEge-7GC5Jxc%i z2?LK_?aT5kJu@l3{%N5Tx%p^T2$x##`D`<04w$RgQ3Jf=>D1))BJaYm&dvbGG(VsH z;wMosNOO7vOF}-HtN9|+XrFB!OO`vmU?BC2VDyc>9&-8JA--RTDM{R^P(Ly~8sw{x z?8{JQd@03iiDQYVL5!JRsTfi8-@VVsw9TTO;(}#@jPEa_d$W&0b5}(R3^AAuMzeKf zLk*=GXamWkmMl;C9~=gfqUwFsd-YEu%#Zy6JtQREs76w#sq>{-?d?uB2eQ6} zxEz9+ztX$B*tp;h+K06)Q=+R$gG>KD%75b1GYynIJUn&HD9%IXc8fxRmg`B>4#bSD zv5!nl-*K*EG1~M!L0fo9kMFE}6aSeTHa=6Lpj!ruk3z?NE?3l{97S>7A$}H(BF~Gl zE&?z+WH(mqQmGR?BQf_}xX-A#P0Dtm!vg|%TmeT7?)S-Br)R_k{V>(@^i0TUI8~YE zT2}&?SVWxknkky?<*CD+9rde|C5Ljt1;lP{yKFyGJH#&0U`Ch)rW0E$V;WWO>!caL{h@*7rd0Ijmdebu{Kdx-QFVb1VOX3g>pmdP4= z`N89ToeOpc=LY+IGQrMRVNO#KLU!ZiJyJe}qg#ZAL}xudNh5q80*pq9XoWjT1>K*t z#2hUT)$^}UR6h+cMjqX$KOVGy^T%8$*l}Lr7YF5!>C5m&&X=o_HL;mV)cY8{cd!oP zYc#+1-`%?je*gkD90dD_v5V+|jad5OdjE02p5wShnO|DRYM9zLyPR*`h@!UQWNMnQ zcNsRajw1=xYC306#gM+@Ij6}x7G0vO;0Kz|d8>*MO ziK`ZBMap-ohCla z2_+;PY1%{s6FHi#74zc_EJB9n=9bxu!IH~OAn*qvNHE_WC#04M0Nb;?AcBNO2Z?9m zu!gd&B#*R(d~KJ#P)A!f%_Rn%v?AA5n~{cV<*VOCnT5)ZBAGOvf#fH`Y=2Ey1Q28> z?3f7-WXgW#Ej8(MRLxTQ=x9C7G7i9X5>tEd}@1F{M>zeBGcXN2-GfCxKHj28KUQFAS!Qd^pz5DTIjpZ z)N@U>j8m z6+*zOl?)h5LqJEBWC%MoXaWnl;QcIqkACa-_}U*0{vv?F{cVx?L>r~n>)mxlZE|u> z1NGvMo#Wg#Sv^=&j}1p3acXUy97$R5*`DwK(yf3qol+HyJBZ(-C$wCy`jtk)) z54#tQ|A0)i?U%a!V*jDN$x83a0N|bzz4_0Kzn%+91>RkCg-B}W=qGP>yt(VC9ZU-Y zsS##7z6(Li+f6y-TYq)tkJA&oaC$X~%eT=-!-4T|HGgdUXX#cLql%9VWwdA7i4)7l zFo_dgXC!h5^(Dxt3+>9p2qo1cNl3L})K*-ykiJH5CFJ{?p;lco*tMptIR4qAr&G09 zoaPg1tUs#Q3`~FYQ?sx2#&FPkc)eB1FvO@fsEjIFbJ#t=NUeRlzdos1&N6&Ks@zu+ zp;NsWZ+W-Yhw)`;O0yph>+IYAfTKSpCK4~+Qe#QmdzE@qZ@ra@ZQ@a;BsVW6m*p9XTw7lJI zcCG(!mGttWiVIoCzV%$dway#u5tbT~{d(ue;ddh6usxBOURI?j{lRXpXhBrjQBzcX zv+YBhZ^zseMw`;lVAV&~q!`7OMC}e-lf>}@K8Sn;68`=B@J0rst$UT}OPesou#E0O zV>V%Y7r>CK*cHvT^1aW%?z1wMeuPDDq9FU^e70h?W%af>Su=;K+G;Go)dDhcLW234 zu&-Hi(h@dnZ@|8X`S853=-7taF+JG2Y6*Stw{-tc26dqa6mKz#sJF&AExxDvVx=S2 zFX(eNkI26{-AI=_fz|V4m8S3z@SNPXKr+HWl|yy=7Dw^I`WY&!JdT#UC{6$)-E(A0 zYqpP`G%U#}o>?Dk3DBO2R{Pz3b=#VNTS?@-C-HL;Q4w|P(M3l@TA-j{z0&@Q&;Z9t z&yHbDZ9_V|&h6|~TlR|V-c9RjhcXhUMhqjBowg>d_5<6wG!Xx`&)#Bnew)0uI$RJz zChk<~I|LKV@_6^EL8U;;Ot@U@biDO&IIOj>3XbI%eOphKx(7!D2^kgp15NN^MzSlk zH9J5dOr=0kxPzpIMK++|Hh;zseoO0FbP7)-ls_+W)u@tOp6Z)sTeD&js|j1y*di1* z$XuQaGB2*7Vqbh5L%qmnuG4P`w36E4T5bk17ScOP({$BP(!)Vsm#W^mg62sRrz)-= zNPFWAZbmEp5UV@;x*P5$XRg)rP6R)S8%*Nqo1T9v>Ya|}hWOm69u(Sye#5a_n#5hR zUkZXmF@==&oU9bOZ4Twd#G6>LtiB%AFWGcIjyUw6?9p&L+w?fstRd}FuCSgo$I6y5 zHA%7$Bym>aK2*+CQD}mq5VBsb^Y>yeU+6x4S=O|U%vQ`84byg+)SWLIfb`1baTz4M zw7R2M$iG>mSwrS*$dUm`gxbY^s#&2q-cHyT4hDpjt8y`Ofu#KNc^pR_+Y6oRqq`=? zlAV#v_RhrImcfcH2@k-`62U%9X2L`;-E#IlMkDSQJFWOji3V4RD8%{B?n>0Ql)=mr zaba?tJ-qLF=JIH>$l0#0a2%Mjj53pIjTrYa{ zkp1#jMibC(mh;kW2*|_x+hkHRcXsg8VWqMOONy%-Mt0iEhtk90uVq{JeA~EI3-!+H zM6bz1dhHqpb=MotZ9KwUHWN&-Mv59`U}cwHt|e@^i482Fi_{>9443b`bt$IgR2_$Ti1d!zs!Zvv`4d5j%(MDyOm7{ zZ3HTiuHV+9MU=H}l$^AhjY|uPP)){;gUFh9+Rlo8#`>|e`){| zvWuez_9O5WP0;Zfo}dyiLXcrycUHK)I{+C!9MN&n&W0T&SiDS-c0OSvrm2aP3jg$;xb{IJ`0}>@g)o2 znrrnxa`M~9cU7Y)xIVa8D6D>d{ns`lHF4$j+eB0ZSR_gePJs5mzg)`1B~KT2wg=PX z!PSATh#fAc20c41j{6LQb=^sr$c-AzRqc&w;r-)?-lJ31v(Z_@=o}=LV)r<@2j=B> z91{2z6<62h1R$xIrNT>Bl}fG}?G1|BLIbRhA9ee#-ZeEHSG>y`lv@GpLg;vz9^pg- z6I45)YYS(dF?)_9yoF)QGiylbd$COF z+aH;98z#=4MDfFl5zh*jbl!a3XZ2(~IWUOfHwkn-*%B{lgnw?(T6E9e=de1u^~2-* zbds{*(p&#gwhOhRNb!Wm4nJEp(|}*>vs7C&qFU^zI`p#mR`8FWxp}AzhncU!!O*l2jzCQ<6JcsqADXFEr`JUPWcT~_r5mPxqtM7jHj+3s$fzwKXR z0PD*VK!NkWwnWMm*bj4hD>92>i6j*t?sNHElo-4ob1!^bAx&?g8le)O{9aU7RCOj7 zz1ZB{TPZtoOqyCST?i2)-5*EF;F91RHz7BhtO?L^Y`)i@CK1MNvz3B*)Omy4RWHbC zc~m}jeKJoeuq1(ZCuU+4(|%DB=#>44J}skaLHPc(3uL3#DJ4(mbRewlx~A?%P1{_j zw$5q8`I*b%=#l?a7`cn|l*f6!R)@#=BKP*M)G)h|KQ8);5r{lSM&NA$XA@2c5i}wo zb2`~#?}x%2@2#$AyBBUu28JSrH{pU1J_&0Q-W+KS*iO$qM60&@5L_gN4{(_tU4?4DbpeTxHwQdQhu2-txnQcPDv~%k@S+`mLE=HjH;5ISW>kQk#-*NYg zHEZyqPm(J%Za8)^o7gHePAPE3ReoEk;Mk}{$4O??fk?1vk?Qh~|3vD0nj&t#pKj~j zJ0>fEqAJ`2DxXvL_|jV?H)5uh&(NAr(;d=O)9}Iz28}5SzFYW|!>^RzjW^EMz?2 z1xcX!S_Py+T7$T)gSmkD!|wbkmhW&iuCd^8-pN9Z#kzj^*Y$*bDXzlmovPZRue4l3w~h|-O8xjS-rdZg|lve@zS0VA|COMZJWY~a}`|2KbD*aP^!{ppywVDoWX zf$um3o%rauGws})03PgmiWsreKX)&&Ue|E3?5g6Q&$8}2(|$10#pnF90rmsJYyk>B zU5GdR(Hv3sm%3U)A&0{?NmblZCD;gWob7S33?+`l#fLzJOoW%5!yR~58+!)e#9XZZ z*6k{w&ACe{ptaa%tC zt^SB^%$r%TF2OI**=Q)I&6Jk05O=3g(6+(xo>hOkBJHuiVa`TC<+&<280%g-TJ=@e z_gjPYFybAa>#A2+##nvkvOox}D?y?d#FRk@jOkU$3vO_e1>>~{ICE2BZO;^Hh1;W(ey5o&n$F+qKov{z^;h%;SfeQaZf zeZ&%p@oD29rDc%I3J^H#G0;dd)KM!esyccRGatPevuEcKJ~v!_Tva##UrqG2_?O2x zK!Llw5p#p?SGfBz>6B&7!X8c`qo7kU0F3jD*UablM~kH6zJMA)2HoYiW$c>l`U6+7 zUW^LxK}bQQuHoUV;o6ArIqHCtIbBoR41Rxv_&96LFAiRnMF4Y+c`E(NlnZEkFRAB?dZK4waC&9H? z3&Wl@f;9^S>LbJ^imuzC5sSMQV!n`aID`FEqu8}N-WE#kM)>CO=^Te85~d;5hs#?| z7EvJf*j_PEun0|^GF8(Vvkf5Sf(+JG9oF>Bo7NbI>C9h2>7F7B_;k)FYQ^QqmTbgd z820lQCn>SDJ#Xvvb!S}$5Iv{6ZB7qE1{lm)2VBGIisH-WIw&pgSQ*6!>>dkt2+N8sjVV?!xW`x_VPAUF^VH_^s z6%B_(q1e5lL-|0ny}*(?cK;KTGq`TfA|c&9k$5Jm1eO(t0yvCIJVxk$AQ|U}(0Ur} zJTGQI?N9{IU?IDA;?hD5H7VL}3&^{~EXK{FEuc0JPPWsMspM|D_dC}VwjU)_yDw#| z?&KCq&)IT$22`(e#emki?q4ITHo;-Cywt&lK&W|UW5FG5iy(LcGo+c60fkn(chB$s~!vc{_qRa_`f_LnBBc58JT8vlZ zm+=*qms$Q$a0ehnz4&FdbR3^@B(tV*W_ERkFo$BSX8oH>8C?yGhv-@7bLW_=A7^x3 zx4g>)ej=ImrFd^eC3c!LcllkqgAMxN-RntJr_%67yT)1g9ba&}?_Sc>%h;#PXKNvD zYHCWT)FlC-RzAqN`j9CsfTQgkBh?o~H+%tvM_5D1gm!6Pp8y5~VN7`7q^Qny)@(Ru zoMc$n1242^z%4<1fH$7gEZ)S3RCF^R5VBO$dUm@VMkFioXG|$pKCI~gH1O-I&NdCy z<>o^-^H--gUDfMeeNN!EK6%4iw~Ax8<%wzZ^)1@xaz0Uzxb@G|_m`O|3Q}RIL(XI0 z1RaLe0WiyE&?*sCplvV6Bl_Q1_E$fX*)hULeBxaf1AyrgM}`>-bWip4nvDwdXgQE^ zPHU6DPB7j~cK&!(sv>)6gZtfnN4p!^d66}5wo=v#qwhWN6cI%mMN*Norg{4N+b9N5 z%q+ir92PmqlIIgft;ZlvU zL{fyz6TK4kI9?~Uwn`!5K9fzYR`O^c)dCf@WBw#cdQX${#6nPu4CS{#_(eobVEHx(8X~>LVts*d~3B#$j$I)@>hjQ z9YLq)fBE+-*!AKTUSUvGXVc2E4#ZwOK+$qr13%uZVX6WfWi|4I%%BTI-_F)OMY9w3 z?za;CdHI1SH{Cafp$E=E&%5a*jb4Pzgj?w)cIp4*Hh@$%{*g*zdUV5zsD)o>s+|mU zC2_+*sC+}`Pz$KVVV&=jLFga*p#m#`(_v;!!y))k z$r!xYd4R_3r66-&a|3gl`|0%-!57c|@8|vCX86eUc-JM)e5_6>4zfZ1fas$WG=zh@ zkj&0&nL$@=6FceB%J!3g`)e-nXd}Ci8*{MRE)qs|TVgfT%T#B9C3rU@F6&f!=iPS6 zT}%z%hCY2>ecPc{D)HXTAY1d-`9d^(Pxogp1I1N2T|og#hF(W;*a46IqP3-exiCq*!+7eI19V7T`XE0eWq%od>X z^Fy7KQ55NaiM{|u!e;s7Snp$DI@T4ncz01w`1K`X?iKym)a?@;{ng!EDf7CzB?#Q@ z`;ET_^1mfn!YH>Kzh4#9$ z!E7BMr!U>-Y%Sixm84;B7l(K^4C0BLuwbi?U5>lkdH$)QT{ureaS;!4$f>p5;Ocys zf39+_xfRm!Gr#=Sw_8tuOv->3l%a}Wq9aEL@~QvRyPHBFSf3=<@vy;Sv*tRO+KJq- zPN1iy3qef7=$M8iC1C0S{dc~&bD)+4(`QiEkm@e zg{neqryp;@^X(@=7Bp9F29npUatZS|K{ zNQ%fhKyN(p^{z!n{=C%2FB`PMyU*k3PNnVNZJ)f9Zyibq(g;&(I2$}fU~0q_aCW!T z3TJDWkpHPf{#U}6EBEqa3LeY=^KOmiZ)Zi>9E4A1)rqk*EYzf%hdMU}Bc9cJv}A8> z><*X`33|YL2(L<63C}A+*MnJ%mc-+U?Yai1(Mo1g2PoJvbd0IfqM+l6fRKVFVtn&b z&g^v9Wixa=cB#7@-M2e-{FTFPjn*oMU0)tep&^EO-CJGFPodWX2%rtg<=B^A_&>t^ zv*JmqWI1A+Spa?s!lPby6()^TjYJ>4r{*LZWMs;ig)dY_hMN9JlHcicq~i~L-dj@o z=2xSytc5^q;dx>o2~$aWg@k(eWUgty1wyK9fYz)sq6Opg@VRaqNK=}pyf zr!BWV3}mt%Eb?-#cK5UHOUS<_VG(Jf(eJBOA>oGV}0-cYw@ZgZX+8XX%j8WkVXv&fP|1Mq63Fkv?2q>4US<6kZE^=;gW^AMaeNhXaphLL3 z4OKzK)|C~Mw+9M`V^VuTjza`92(3R^)FZj-`AS${o!(AO%TmsL=Qm!)C!&&n^c)m8 zj@JrfFQCI$Q~(_wnbTaj7HpAZEwuizI)kwhDpnwTe4~lSBab1I-^=U}zSNQ)+NnYA z<$N0g&)Xe_4-;r7du_;C{s-s&Z_nbDhSopv2{*mc%vvr{m#O1TL$wY<#{ez_4R8rK zT!8mJiH|MPAax=;U9??{j;9@JHDs~7`Y{wPmtdKkZ@&&R4V-Lr>d#+xTwZ=?kx-6d zsl2Ds=?B(4ad8XQyV9R774<7B_)>#0{tN8Gxfrp@nPKheGU2u!F~_~gy)iVv%H8uu zF2Ijh*WJQ)@l8T&{ti51Q!R2hbkpTC*;UD1T?vrREQXg z)(T36?oG2~lfQB2LMLkj-41o@TElG>kkOi90sv#BfApswd4^(U70tFz97%u|M6}b< zdj$N(n|wA?fu!ghhlZ0y$Nx_e{?`q8JwZ<^W}}ttEt;sZEv)h5$q>4xvpSq~8x}oX zRe-rlOxvqI=U`nzQ^@zPoGN)6eXZWfo<2vRTw{w~5K`v;1LyE$r+48ToVg{i8SDhy zlrsicFsqQ?rA}mF14Hg&TPKVppxscN<0NxpvQ9V>nO9s@C4WqYuV{){=$`OEAfHA?;hrz?y0!oM98^CZG z9~eSGZO2p^>a+0e3@86XUL6Z%l%YQ0k<%{ng=xNT=8P8+J`H5A8>e4B_+b>;^5bLE>*YoEP&6 zwz}~pKI^ME8C1@=JJu-bHnDAfnZ-y?X*1Yz0(CU;Hd=rDg;_+tjNb1w+OX2Pnr*-R z+WsW1$N90P*;rckgrIE-e;4QfEyCIek-NkW(k|~84x3Xyxh%Aha%5jrb?F8KU=zt( zzr#jW)Cix{gFX+MAB;z9N>?9&2qoIC)33oz=!#_^4IewB(vaUeRdyar_cL*;=tl&85?d|k-wuNvnbb#r8O4{AEnA%}lVs7hT z#k{SA;Q`oSZUv~nFbC4UKOV}?OhRlp_-Wg>Q(s%Cb3a|PcfWemS0gkCXzIWNy~Ztf zQge^5Qk4lcpsAO(8(eBnSZdho=u3K9IFWn;q$pr%O&Vmk>q0IM4fenK3HP3gc)$wQ z3&-0-A*yP`UvjwVSjNgF0tGXCPx6c%)WON^mPHL+8Murs<1Zu7DS~}~2>a#I0c^Qg z)Q`I_wqeIIF5U}h&8IJQ=4cGmJLQw^gmE4&pau9gD`~;%hLa6MTdN#I1yfu4HJbeG zm)dTR=q72(hP4Ew59lW>M8S^Ip=A|-4^GW|Q(oNX)~Oqdc+w|wZmvq?JmuVLM!kaj zgP+-3YY^}b-9p&st~c>sSOiSLpP#ZYE9Y?8k$TL2Om7+VwhwU9fKc#{LM5Ze@VJsa zJk)pAD-|lOwVfS@cN9RLs8F72T_bPYo5) z;EWkY0}7h*sn&jS1b$Z2Ix#}SOT$UyR%bUD4R!9uF`2O5OCom{OyCu@uiB9=kXd@X zB6jDh+8aVd+-}I8JAp&6I@7vEti65`UEg=Es*YAZ^d2aFF#U=5Mr zFf5Zz?V<-D-e0Kf&5mxvKk?pQBs9)Q8tM%S7nkxjTSyyHbrY$B-T?BJo@EdRL7C;F z&v{p+kgLxw`=DZh?D`NR_gC+0*V_(&fl@PHu@=3G7)KS*&wL>j9IgW zJrt&OIHYPf#cR^plRypG?dP~ftS^Y%WpHiOZ20)N2byGc$Nb^`loL!g%EY86eEfM( zMd75y`C^>SeAfV^(jZFLIequA*SR1X_tI1SC#e1Ym7&=4j9urh4Vz?PkrwPtxNV`< zzS?NH9Y!aHzYF3Qk^TNwhr9uNA%YkP75_V=713v-LmC8?uF)MlY`ivxISid perET2e{P<9XDXCIdA05Q+Kq9U054}{XC&}XLQM8q!4ti={|~){>aYL+ diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index eaeb7d4812..d060edaf4b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add new check `teams_meeting_presenters_restricted` [(#7613)](https://github.com/prowler-cloud/prowler/pull/7613) - Add new check `teams_meeting_chat_anonymous_users_disabled` [(#7579)](https://github.com/prowler-cloud/prowler/pull/7579) - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) +- Add support for m365 provider in Prowler Dashboard [(#7633)](https://github.com/prowler-cloud/prowler/pull/7633) - Add new check for Modern Authentication enabled for Exchange Online in M365 [(#7636)](https://github.com/prowler-cloud/prowler/pull/7636) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) From bbc0388d4dfb7e6952e611d6b958f1a677c766bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 5 May 2025 16:40:59 +0200 Subject: [PATCH 253/359] chore(changelog): update with latest PR (#7628) Co-authored-by: Sergio Garcia --- prowler/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index d060edaf4b..1671fff7e4 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -55,6 +55,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Improve compliance and dashboard [(#7596)](https://github.com/prowler-cloud/prowler/pull/7596) - Remove invalid parameter `create_file_descriptor` [(#7600)](https://github.com/prowler-cloud/prowler/pull/7600) - Remove first empty line in HTML output [(#7606)](https://github.com/prowler-cloud/prowler/pull/7606) +- Remove empty files in Prowler [(#7627)](https://github.com/prowler-cloud/prowler/pull/7627) - Ensure that ContentType in upload_file matches the uploaded file’s format [(#7635)](https://github.com/prowler-cloud/prowler/pull/7635) - Fix incorrect check inside 4.4.1 requirement for Azure CIS 2.0 [(#7656)](https://github.com/prowler-cloud/prowler/pull/7656). From 9d788af9322787f16f2bf8356cd3aea929dabb5e Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 5 May 2025 16:46:32 +0200 Subject: [PATCH 254/359] docs(m365): add documentation for `m365` (#7622) Co-authored-by: Sergio Garcia --- docs/getting-started/requirements.md | 310 +++++++++++++++++- docs/index.md | 2 +- .../microsoft365/getting-started-m365.md | 205 ++++++++++++ .../img/add-app-api-permission.png | Bin 0 -> 158671 bytes .../img/add-delegated-api-permission.png | Bin 0 -> 146443 bytes .../microsoft365/img/api-permissions-page.png | Bin 0 -> 332016 bytes .../microsoft365/img/app-overview.png | Bin 0 -> 337670 bytes .../img/app-registration-menu.png | Bin 0 -> 199345 bytes .../img/certificates-and-secrets.png | Bin 0 -> 385155 bytes .../microsoft365/img/custom-domain-names.png | Bin 0 -> 212586 bytes .../img/directory-permission-delegated.png | Bin 0 -> 206787 bytes .../microsoft365/img/directory-permission.png | Bin 0 -> 195715 bytes .../microsoft365/img/global-reader.png | Bin 0 -> 167288 bytes .../img/grant-admin-consent-delegated.png | Bin 0 -> 470214 bytes .../img/grant-admin-consent-for-role.png | Bin 0 -> 167098 bytes .../microsoft365/img/grant-admin-consent.png | Bin 0 -> 448683 bytes .../microsoft365/img/microsoft-entra-id.png | Bin 0 -> 270427 bytes .../microsoft365/img/new-client-secret.png | Bin 0 -> 295082 bytes .../microsoft365/img/new-registration.png | Bin 0 -> 392016 bytes .../img/search-default-domain.png | Bin 0 -> 110798 bytes .../microsoft365/img/search-domain-names.png | Bin 0 -> 68329 bytes .../microsoft365/img/user-domains.png | Bin 0 -> 199133 bytes .../microsoft365/img/user-info-page.png | Bin 0 -> 254334 bytes .../microsoft365/img/user-role-page.png | Bin 0 -> 150596 bytes .../microsoft365/use-of-powershell.md | 12 + docs/tutorials/prowler-app.md | 7 + mkdocs.yml | 2 + prowler/CHANGELOG.md | 1 + 28 files changed, 524 insertions(+), 15 deletions(-) create mode 100644 docs/tutorials/microsoft365/getting-started-m365.md create mode 100644 docs/tutorials/microsoft365/img/add-app-api-permission.png create mode 100644 docs/tutorials/microsoft365/img/add-delegated-api-permission.png create mode 100644 docs/tutorials/microsoft365/img/api-permissions-page.png create mode 100644 docs/tutorials/microsoft365/img/app-overview.png create mode 100644 docs/tutorials/microsoft365/img/app-registration-menu.png create mode 100644 docs/tutorials/microsoft365/img/certificates-and-secrets.png create mode 100644 docs/tutorials/microsoft365/img/custom-domain-names.png create mode 100644 docs/tutorials/microsoft365/img/directory-permission-delegated.png create mode 100644 docs/tutorials/microsoft365/img/directory-permission.png create mode 100644 docs/tutorials/microsoft365/img/global-reader.png create mode 100644 docs/tutorials/microsoft365/img/grant-admin-consent-delegated.png create mode 100644 docs/tutorials/microsoft365/img/grant-admin-consent-for-role.png create mode 100644 docs/tutorials/microsoft365/img/grant-admin-consent.png create mode 100644 docs/tutorials/microsoft365/img/microsoft-entra-id.png create mode 100644 docs/tutorials/microsoft365/img/new-client-secret.png create mode 100644 docs/tutorials/microsoft365/img/new-registration.png create mode 100644 docs/tutorials/microsoft365/img/search-default-domain.png create mode 100644 docs/tutorials/microsoft365/img/search-domain-names.png create mode 100644 docs/tutorials/microsoft365/img/user-domains.png create mode 100644 docs/tutorials/microsoft365/img/user-info-page.png create mode 100644 docs/tutorials/microsoft365/img/user-role-page.png create mode 100644 docs/tutorials/microsoft365/use-of-powershell.md diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index 81791b1b31..d2ebd8a12b 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -130,7 +130,7 @@ Prowler for M365 currently supports the following authentication types: ???+ warning - For Prowler App only the Service Principal with an application authentication method is supported. + For Prowler App only the Service Principal with User Credentials authentication method is supported. ### Service Principal authentication @@ -145,7 +145,9 @@ export AZURE_TENANT_ID="XXXXXXXXX" ``` If you try to execute Prowler with the `--sp-env-auth` flag and those variables are empty or not exported, the execution is going to fail. -Follow the instructions in the [Create Prowler Service Principal](../tutorials/azure/create-prowler-service-principal.md) section to create a service principal. +Follow the instructions in the [Create Prowler Service Principal](../tutorials/microsoft365/getting-started-m365.md#create-the-service-principal-app) section to create a service principal. + +With this credentials you will only be able to run the checks that work through MS Graph, this means that you won't run all the provider. If you want to scan all the checks from M365 you will need to use the recommended authentication method. ### Service Principal and User Credentials authentication (recommended) @@ -161,21 +163,66 @@ export M365_USER="your_email@example.com" export M365_ENCRYPTED_PASSWORD="6500780061006d0070006c006500700061007300730077006f0072006400" # replace this to yours ``` -These two new environment variables are required to execute the PowerShell modules needed to retrieve information from M365 services. Prowler will use service principal authentication to log into MS Graph and user credentials to authenticate to Microsoft PowerShell modules. +These two new environment variables are **required** to execute the PowerShell modules needed to retrieve information from M365 services. Prowler uses Service Principal authentication to access Microsoft Graph and user credentials to authenticate to Microsoft PowerShell modules. -The `M365_USER` should be your Microsoft account email, and `M365_ENCRYPTED_PASSWORD` must be an encrypted SecureString. -To convert your password into a valid encrypted string, run the following commands in PowerShell: +- `M365_USER` should be your Microsoft account email using the default domain. This means it must look like `example@YourCompany.onmicrosoft.com`. -```console -$securePassword = ConvertTo-SecureString "examplepassword" -AsPlainText -Force -$encryptedPassword = $securePassword | ConvertFrom-SecureString -``` + To ensure that you are using the default domain you can see how to verify it [here](../tutorials/microsoft365/getting-started-m365.md#step-1-obtain-your-domain). -If everything is done correctly, you will see the encrypted string that you need to set as the `M365_ENCRYPTED_PASSWORD` environment variable. -```console -Write-Output $encryptedPassword -6500780061006d0070006c006500700061007300730077006f0072006400 -``` + If you don't have a user created with that domain, Prowler will not work as it will not be able to ensure both app an user belong to the same tenant. To proceed, you can either create a new user with that domain or modify the domain of an existing user. + + ![User Domains](../tutorials/microsoft365/img/user-domains.png) + +- `M365_ENCRYPTED_PASSWORD` must be an encrypted SecureString. To convert your password into a valid encrypted string, you need to use PowerShell. + + ???+ warning + Passwords encrypted using ConvertTo-SecureString can only be decrypted on the same OS/user context. If you generate an encrypted password on macOS or Linux (both UNIX), it should fail on Windows and vice versa. As Prowler Cloud runs on UNIX if you generate your password using Windows it won't work so you'll need to generate a new password using any UNIX distro (example above) + + If you are working from Windows and you will use your encrypted password in a different system (like for example executing Prowler in macOS or adding your password to Prowler Cloud), you will need to generate a "UNIX compatible" version of your encrypted password. This can be done using WSL which is so easy to install on Windows. + + === "UNIX" + + Open a PowerShell cmd with a [supported version](requirements.md#supported-powershell-versions) and then run the following command: + + ```console + $securePassword = ConvertTo-SecureString "examplepassword" -AsPlainText -Force + $encryptedPassword = $securePassword | ConvertFrom-SecureString + Write-Output $encryptedPassword + 6500780061006d0070006c006500700061007300730077006f0072006400 + ``` + + If everything is done correctly, you will see the encrypted string that you need to set as the `M365_ENCRYPTED_PASSWORD` environment variable. + + === "Windows" + + + How to install WSL and PowerShell on it to generate that password (you can use a different distro but this one will work for sure): + + ```console + wsl --install -d Ubuntu-22.04 + ``` + + Then, open the Ubuntu terminal and run the following commands: + + ```console + sudo apt update && sudo apt install -y wget apt-transport-https software-properties-common + wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" + sudo dpkg -i packages-microsoft-prod.deb + sudo apt update + sudo apt install -y powershell + pwsh + ``` + + With this done you will see now that a prompt running PowerShell with the latest version is open so here you will be able to generate your encrypted password: + + ```console + $securePassword = ConvertTo-SecureString "examplepassword" -AsPlainText -Force + $encryptedPassword = $securePassword | ConvertFrom-SecureString + Write-Output $encryptedPassword + 6500780061006d0070006c006500700061007300730077006f0072006400 + ``` + + If everything is done correctly, you will see the encrypted string that you need to set as the `M365_ENCRYPTED_PASSWORD` environment variable. @@ -184,3 +231,238 @@ Write-Output $encryptedPassword Authentication flag: `--browser-auth` This authentication method requires the user to authenticate against Azure using the default browser to start the scan, also `--tenant-id` flag is required. + +With this credentials you will only be able to run the checks that work through MS Graph, this means that you won't run all the provider. If you want to scan all the checks from M365 you will need to use the recommended authentication method. + +Since this is a delegated permission authentication method, necessary permissions should be given to the user, not the app. + + +### Needed permissions + +Prowler for M365 requires two types of permission scopes to be set (if you want to run the full provider including PowerShell checks). Both must be configured using Microsoft Entra ID: + +- **Service Principal Application Permissions**: These are set at the **application** level and are used to retrieve data from the identity being assessed: + - `Directory.Read.All`: Required for all services. + - `Policy.Read.All`: Required for all services. + - `User.Read` (IMPORTANT: this must be set as **delegated**): Required for the sign-in. + - `Sites.Read.All`: Required for SharePoint service. + - `SharePointTenantSettings.Read.All`: Required for SharePoint service. + +- **Powershell Modules Permissions**: These are set at the `M365_USER` level, so the user used to run Prowler must have one of the following roles: + - `Global Reader` (recommended): this allows you to read all roles needed. + - `Exchange Administrator` and `Teams Administrator`: user needs both roles but with this [roles](https://learn.microsoft.com/en-us/exchange/permissions-exo/permissions-exo#microsoft-365-permissions-in-exchange-online) you can access to the same information as a Global Reader (since only read access is needed, Global Reader is recommended). + +In order to know how to assign those permissions and roles follow the instructions in the Microsoft Entra ID [permissions](../tutorials/microsoft365/getting-started-m365.md#grant-required-api-permissions) and [roles](../tutorials/microsoft365/getting-started-m365.md#assign-required-roles-to-your-user) section. + + +### Supported PowerShell versions + +You must have PowerShell installed to run certain M365 checks. +Currently, we support **PowerShell version 7.4 or higher** (7.5 is recommended). + +This requirement exists because **PowerShell 5.1** (the version that comes by default on some Windows systems) does not support several cmdlets needed to run the checks properly. +Additionally, earlier [PowerShell Cross-Platform versions](https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.5) are no longer under technical support, which may cause unexpected errors. + + +???+ note + Installing powershell will be only needed if you install prowler from pip or other sources, these means that the SDK and API containers contain PowerShell installed by default. + +Installing PowerShell is different depending on your OS. + +- [Windows](https://learn.microsoft.com/es-es/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.5#install-powershell-using-winget-recommended): you will need to update PowerShell to +7.4 to be able to run prowler, if not some checks will not show findings and the provider could not work as expected. This version of PowerShell is [supported](https://learn.microsoft.com/es-es/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4#supported-versions-of-windows) on Windows 10, Windows 11, Windows Server 2016 and higher versions. + +```console +winget install --id Microsoft.PowerShell --source winget +``` + + +- [MacOS](https://learn.microsoft.com/es-es/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.5#install-the-latest-stable-release-of-powershell): installing PowerShell on MacOS needs to have installed [brew](https://brew.sh/), once you have it is just running the command above, Pwsh is only supported in macOS 15 (Sequoia) x64 and Arm64, macOS 14 (Sonoma) x64 and Arm64, macOS 13 (Ventura) x64 and Arm64 + +```console +brew install powershell/tap/powershell +``` + +Once it's installed run `pwsh` on your terminal to verify it's working. + +- Linux: installing PowerShell on Linux depends on the distro you are using: + + - [Ubuntu](https://learn.microsoft.com/es-es/powershell/scripting/install/install-ubuntu?view=powershell-7.5#installation-via-package-repository-the-package-repository): The required version for installing PowerShell +7.4 on Ubuntu are Ubuntu 22.04 and Ubuntu 24.04. The recommended way to install it is downloading the package available on PMC. You just need to follow the following steps: + + ```console + ################################### + # Prerequisites + + # Update the list of packages + sudo apt-get update + + # Install pre-requisite packages. + sudo apt-get install -y wget apt-transport-https software-properties-common + + # Get the version of Ubuntu + source /etc/os-release + + # Download the Microsoft repository keys + wget -q https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb + + # Register the Microsoft repository keys + sudo dpkg -i packages-microsoft-prod.deb + + # Delete the Microsoft repository keys file + rm packages-microsoft-prod.deb + + # Update the list of packages after we added packages.microsoft.com + sudo apt-get update + + ################################### + # Install PowerShell + sudo apt-get install -y powershell + + # Start PowerShell + pwsh + ``` + + - [Alpine](https://learn.microsoft.com/es-es/powershell/scripting/install/install-alpine?view=powershell-7.5#installation-steps): The only supported version for installing PowerShell +7.4 on Alpine is Alpine 3.20. The unique way to install it is downloading the tar.gz package available on [PowerShell github](https://github.com/PowerShell/PowerShell/releases/download/v7.5.0/powershell-7.5.0-linux-musl-x64.tar.gz). You just need to follow the following steps: + + ```console + # Install the requirements + sudo apk add --no-cache \ + ca-certificates \ + less \ + ncurses-terminfo-base \ + krb5-libs \ + libgcc \ + libintl \ + libssl3 \ + libstdc++ \ + tzdata \ + userspace-rcu \ + zlib \ + icu-libs \ + curl + + apk -X https://dl-cdn.alpinelinux.org/alpine/edge/main add --no-cache \ + lttng-ust \ + openssh-client \ + + # Download the powershell '.tar.gz' archive + curl -L https://github.com/PowerShell/PowerShell/releases/download/v7.5.0/powershell-7.5.0-linux-musl-x64.tar.gz -o /tmp/powershell.tar.gz + + # Create the target folder where powershell will be placed + sudo mkdir -p /opt/microsoft/powershell/7 + + # Expand powershell to the target folder + sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 + + # Set execute permissions + sudo chmod +x /opt/microsoft/powershell/7/pwsh + + # Create the symbolic link that points to pwsh + sudo ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh + + # Start PowerShell + pwsh + ``` + + - [Debian](https://learn.microsoft.com/es-es/powershell/scripting/install/install-debian?view=powershell-7.5#installation-on-debian-11-or-12-via-the-package-repository): The required version for installing PowerShell +7.4 on Debian are Debian 11 and Debian 12. The recommended way to install it is downloading the package available on PMC. You just need to follow the following steps: + + ```console + ################################### + # Prerequisites + + # Update the list of packages + sudo apt-get update + + # Install pre-requisite packages. + sudo apt-get install -y wget + + # Get the version of Debian + source /etc/os-release + + # Download the Microsoft repository GPG keys + wget -q https://packages.microsoft.com/config/debian/$VERSION_ID/packages-microsoft-prod.deb + + # Register the Microsoft repository GPG keys + sudo dpkg -i packages-microsoft-prod.deb + + # Delete the Microsoft repository GPG keys file + rm packages-microsoft-prod.deb + + # Update the list of packages after we added packages.microsoft.com + sudo apt-get update + + ################################### + # Install PowerShell + sudo apt-get install -y powershell + + # Start PowerShell + pwsh + ``` + + - [Rhel](https://learn.microsoft.com/es-es/powershell/scripting/install/install-rhel?view=powershell-7.5#installation-via-the-package-repository): The required version for installing PowerShell +7.4 on Red Hat are RHEL 8 and RHEL 9. The recommended way to install it is downloading the package available on PMC. You just need to follow the following steps: + + ```console + ################################### + # Prerequisites + + # Get version of RHEL + source /etc/os-release + if [ ${VERSION_ID%.*} -lt 8 ] + then majorver=7 + elif [ ${VERSION_ID%.*} -lt 9 ] + then majorver=8 + else majorver=9 + fi + + # Download the Microsoft RedHat repository package + curl -sSL -O https://packages.microsoft.com/config/rhel/$majorver/packages-microsoft-prod.rpm + + # Register the Microsoft RedHat repository + sudo rpm -i packages-microsoft-prod.rpm + + # Delete the downloaded package after installing + rm packages-microsoft-prod.rpm + + # Update package index files + sudo dnf update + # Install PowerShell + sudo dnf install powershell -y + ``` + +- [Docker](https://learn.microsoft.com/es-es/powershell/scripting/install/powershell-in-docker?view=powershell-7.5#use-powershell-in-a-container): The following command download the latest stable versions of PowerShell: + + ```console + docker pull mcr.microsoft.com/dotnet/sdk:9.0 + ``` + + To start an interactive shell of Pwsh you just need to run: + + ```console + docker run -it mcr.microsoft.com/dotnet/sdk:9.0 pwsh + ``` + + +### Needed PowerShell modules + +To obtain the required data for this provider, we use several PowerShell cmdlets. +These cmdlets come from different modules that must be installed. + +The installation of these modules will be performed automatically if you run Prowler with the flag `--init-modules`. This an example way of running Prowler and installing the modules: + +```console +python3 prowler-cli.py m365 --verbose --log-level ERROR --env-auth --init-modules +``` + +If you already have them installed, there is no problem even if you use the flag because it will automatically check if the needed modules are already installed. + +???+ note + Prowler installs the modules using `-Scope CurrentUser`. + If you encounter any issues with services not working after the automatic installation, try installing the modules manually using `-Scope AllUsers` (administrator permissions are required for this). + The command needed to install a module manually is: + ```powershell + Install-Module -Name "ModuleName" -Scope AllUsers -Force + ``` + +The required modules are: + +- [ExchangeOnlineManagement](https://www.powershellgallery.com/packages/ExchangeOnlineManagement/3.6.0): Minimum version 3.6.0. Required for several checks across Exchange, Defender, and Purview. +- [MicrosoftTeams](https://www.powershellgallery.com/packages/MicrosoftTeams/6.6.0): Minimum version 6.6.0. Required for all Teams checks. diff --git a/docs/index.md b/docs/index.md index 1645b3d4fc..a92d4b0444 100644 --- a/docs/index.md +++ b/docs/index.md @@ -585,7 +585,7 @@ prowler m365 --browser-auth --tenant-id "XXXXXXXX" ``` -See more details about M365 Authentication in [Requirements](getting-started/requirements/#microsoft-365) +See more details about M365 Authentication in [Requirements](getting-started/requirements.md#microsoft-365) ## Prowler v2 Documentation For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md). diff --git a/docs/tutorials/microsoft365/getting-started-m365.md b/docs/tutorials/microsoft365/getting-started-m365.md new file mode 100644 index 0000000000..4cfaf1893f --- /dev/null +++ b/docs/tutorials/microsoft365/getting-started-m365.md @@ -0,0 +1,205 @@ +# Getting Started with M365 on Prowler Cloud + +Set up your M365 account to enable security scanning using Prowler Cloud. + +## Requirements + +To configure your M365 account, you’ll need: + +1. Obtain your `Default Domain` from the Entra ID portal. + +2. Access Prowler Cloud and add a new cloud provider `Microsoft 365`. + +3. Configure your M365 account: + + 3.1 Create the Service Principal app. + + 3.2 Grant the required API permissions. + + 3.3 Assign the required roles to your user. + + 3.4 Retrieve your encrypted password. + +4. Add the credentials to Prowler Cloud. + +## Step 1: Obtain your Domain + +Go to the Entra ID portal, then you can search for `Domain` or go to Identity > Settings > Domain Names. + +![Search Domain Names](./img/search-domain-names.png) + +
    + +![Custom Domain Names](./img/custom-domain-names.png) + +Once you are there just look for the `Default Domain` this should be something similar to `YourCompany.onmicrosoft.com`. To ensure that you are picking the correct domain just click on it and verify that the type is `Initial` and you can't delete it. + +![Search Default Domain](./img/search-default-domain.png) + +--- + +## Step 2: Access Prowler Cloud + +1. Go to [Prowler Cloud](https://cloud.prowler.com/) +2. Navigate to `Configuration` > `Cloud Providers` + + ![Cloud Providers Page](../img/cloud-providers-page.png) + +3. Click on `Add Cloud Provider` + + ![Add a Cloud Provider](../img/add-cloud-provider.png) + +4. Select `Microsoft 365` + + ![Select Microsoft 365](./img/select-m365-prowler-cloud.png) + +5. Add the Domain ID and an optional alias, then click `Next` + + ![Add Domain ID](./img/add-domain-id.png) + +--- + +## Step 3: Configure your M365 account + + +### Create the Service Principal app + +A Service Principal is required to grant Prowler the necessary privileges. + +1. Access **Microsoft Entra ID** + + ![Overview of Microsoft Entra ID](./img/microsoft-entra-id.png) + +2. Navigate to `Applications` > `App registrations` + + ![App Registration nav](./img/app-registration-menu.png) + +3. Click `+ New registration`, complete the form, and click `Register` + + ![New Registration](./img/new-registration.png) + +4. Go to `Certificates & secrets` > `+ New client secret` + + ![Certificate & Secrets nav](./img/certificates-and-secrets.png) + +5. Fill in the required fields and click `Add`, then copy the generated value (that value will be `AZURE_CLIENT_SECRET`) + + ![New Client Secret](./img/new-client-secret.png) + +With this done you will have all the needed keys, summarized in the following table + +| Value | Description | +|-------|-------------| +| Client ID | Application (client) ID | +| Client Secret | AZURE_CLIENT_SECRET | +| Tenant ID | Directory (tenant) ID | + +--- + +### Grant required API permissions + +Assign the following Microsoft Graph permissions: + +- `Directory.Read.All`: Required for all services. +- `Policy.Read.All`: Required for all services. +- `User.Read` (IMPORTANT: this is set as **delegated**): Required for the sign-in. +- `Sites.Read.All`: Required for SharePoint service. +- `SharePointTenantSettings.Read.All`: Required for SharePoint service. + +Follow these steps to assign the permissions: + +1. Go to your App Registration > Select your Prowler App created before > click on `API permissions` + + ![API Permission Page](./img/api-permissions-page.png) + +2. Click `+ Add a permission` > `Microsoft Graph` > `Application permissions` + + ![Add API Permission](./img/add-app-api-permission.png) + +3. Search and select every permission below and once all are selected click on `Add permissions`: + + - `Directory.Read.All` + - `Policy.Read.All` + - `Sites.Read.All` + - `SharePointTenantSettings.Read.All` + + ![Permission Screenshots](./img/directory-permission.png) + +4. Click `Add permissions`, then grant admin consent + + ![Grant Admin Consent](./img/grant-admin-consent.png) + +5. Click `+ Add a permission` > `Microsoft Graph` > `Delegated permissions` + + ![Add API Permission](./img/add-delegated-api-permission.png) + +6. Search and select: + + - `User.Read` + + ![Permission Screenshots](./img/directory-permission-delegated.png) + +7. Click `Add permissions`, then grant admin consent + + ![Grant Admin Consent](./img/grant-admin-consent-delegated.png) + +--- + +### Assign required roles to your user + +Assign one of the following roles to your User: + +- `Global Reader` (recommended): this allows you to read all roles needed. +- `Exchange Administrator` and `Teams Administrator`: user needs both roles but with this [roles](https://learn.microsoft.com/en-us/exchange/permissions-exo/permissions-exo#microsoft-365-permissions-in-exchange-online) you can access to the same information as a Global Reader (here you only read so that's why we recomend that role). + +Follow these steps to assign the role: + +1. Go to Users > All Users > Click on the email for the user you will use + + ![User Overview](./img/user-info-page.png) + +2. Click `Assigned Roles` + + ![User Roles](./img/user-role-page.png) + +3. Click on `Add assignments`, then search and select: + + - `Global Reader` This is the recommended, if you want to use the others just search for them + + ![Global Reader Screenshots](./img/global-reader.png) + +4. Click on next, then assign the role as `Active`, and click on `Assign` to grant admin consent + + ![Grant Admin Consent for Role](./img/grant-admin-consent-for-role.png) + +--- + +### Get your encrypted password + +For this step you will need to use PowerShell, here you will have to create your Encrypted Password based on the password of the User that you are going to use. For more information about how to generate this Password go [here](../../getting-started/requirements.md#service-principal-and-user-credentials-authentication-recommended) and follow the steps needed to obtain `M365_ENCRYPTED_PASSWORD`. + +--- + +## Step 4: Add credentials to Prowler Cloud + +1. Go to your App Registration overview and copy the `Client ID` and `Tenant ID` + + ![App Overview](./img/app-overview.png) + +2. Go to Prowler Cloud and paste: + + - `Client ID` + - `Tenant ID` + - `AZURE_CLIENT_SECRET` from earlier + - `M365_USER` your user using the default domain, more info [here](../../getting-started/requirements.md#service-principal-and-user-credentials-authentication-recommended) + - `M365_ENCRYPTED_PASSWORD` generated before + + ![Prowler Cloud M365 Credentials](./img/add-credentials-m365-prowler-cloud.png) + +3. Click `Next` + + ![Next Detail](./img/click-next-m365.png) + +4. Click `Launch Scan` + + ![Launch Scan M365](./img/launch-scan.png) diff --git a/docs/tutorials/microsoft365/img/add-app-api-permission.png b/docs/tutorials/microsoft365/img/add-app-api-permission.png new file mode 100644 index 0000000000000000000000000000000000000000..f05e113e9e564e88aba05a26892a477607572d72 GIT binary patch literal 158671 zcmeFYhg*|N6E_?>s0f0BiWEgaYUsU+NCyS!O?oHvUPVMyr1vVl2kAXh1Ocg`x6nfm z5FkK+eDQeBbIx?|PCe$!2$F%k1v#%x~t7c%ddwdhPx-002O$sPIe!0Kmru z0PwPj39&hanqvz9zztPfS=kqgva$>>TtQa04we9bLPUZNk*;PhRi=T4A~E^<;P~M* zhDS`n@#Ok|O*!&}XnbO(?zh=y^3-<>o8P~d(~-G7d+mprtdWQ1%bg0#uh~^qTvR)K zY2?yL0c(D6^!ftk%56Q%Z7{=t5b!))nz>)D7Vsl(z296GcZxDrb1IK37{Hs2iRKXi^{}k<#rd!}gz; z>IazFL)U~*x2bQ>`(wkqOI+W1_{H-H7>3!BL*feLpUaft0X`@{yS!ri*{AW2x#;qx z!Iw8g_Jq3RQJSmW2Slg3F$~-f%oyME`_e4PsPQOW1b8So*-#@H@2T2)ZZjub9o)|n1{kl z^*!Sq5tk)A$>K1*mLD?ojl9|kADOybzw$qpE{{sE{1IwSbm0YOC3Ndivrs&Z!8>&g z)b=lG(w<`ck}VaOe0_p3(Up?Wqw537t_}h)o3R{Sn4)X_3@PnQ{Cj9Wl1?RHW>;>R#s8jb2 z%f00>dHHCb;X;jGoT!I`cuNe_#_Z^XJlR{1-^fSDTrfVuad?_6%jHmV6*NRvWpa

    |f(w-s@dFnfVKQn|C||Qoq7Zp~3EPh8 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

    BR$4FV=D!am(?d+vY_?f>m3Z1k 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%0Ac&eiH@oV2X2dsMidg-vk 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 z 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 NxCYUWwhm%+TXciWpj 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 literal 0 HcmV?d00001 diff --git a/docs/tutorials/microsoft365/img/api-permissions-page.png b/docs/tutorials/microsoft365/img/api-permissions-page.png new file mode 100644 index 0000000000000000000000000000000000000000..32a7cf2e9e73ec0828ed119ca369790337baaddf GIT binary patch literal 332016 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

    nX7dXsAj9(Dl!(q1NM%ZyE=H5 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

    e7#R@TDy?QeaD*ev_dHgTsj=DmE-ko z*t1E${K|vIl8Z^2i>8ntkx{C>PNY3qLNzd??Uc=*m}Oq?_qy5QFR`>d+cQ8)28g!F zFC~-WHf8o0v9YMFK#fC^%a=zSY{}(Dp$DZ7uBzeRcpu7y`g$~>Y@WBy9y=>voQnD$ zs|;mLP#=X7Ip)-;#_xpwz1~OawPrDTl7YJDX%)<1X=v2yanQ1>FG(QPfI7+J^_L}r zV~?J0@b#G8V!sjj)`KtPtPIf^#b_DevSg53<^SuOqNmxz^Cwb{&9Cl8_Vt(@?uGi# zt~5J^=XS+R_Pvz2mzWk#i$N)nW9Y66PbDhiSX2S>Ojuu8)9L5ezjR0R_5i?7KPNey zw7Ok~iuQ8hc`ZiA$CIp(5ARBj??ViVO2Fy!!ny=<=c;<1Tk5up*b<0cM zY%g8{q2k4J=W)s7xpq;q8;noRv$d$Hwv}0s&!etQN|t4Pohz=X=$zg}1My8)tIsyF z6z@so5c2mh5?s_HT)}R9(W)r_nt_;uzuO;CoRz;;LA<3c^Q<+yuS{Ut;01U89U>}$8~tsSr|Q|Z@?I8o)Zt{J^9WYV+0 z`+2d{il!9^K{324syzE)J-T-z!V^(w1NT2%is&yG8o4O9Xr7rr<%S4G6#dE6m87P4 ze6t@ejh`StZ@nREm|R3BhZ}HCNMvF;$38g}woT2~UY#dYeC={&Gd1!FtV3)goe0um zutEn>g$gaZYO6TOf&{D^yCxq%yVDIi3kuOp*-MG$mekhC74K-NxZOG#(gGZXg33F; z&HKC#e;#E7XzRRfZ>E`}U=Pn9?;V?!e`abAoI8Z67vy9_{eu2Vj~=KCKiS>l zFm3EaOmC&xKYm_UQcZR--=o;t zHk<(jZNGZmPjhx=HQyC3YTZ-GdJ>#Kzb82Ex7ufwYP@>9QaQBMXIu~-DSln}+Zgc% zC3}h0_CGO)kU5G0Xkd>^`ypeb|4`3QWDI>a`jL#*rU*vS#dAr=BeZTJs6svx&>%&> zh!gGv0QA&g8BMYHsUgPPrLtyg@E7p(#M|4)lK*@7UF_TKU+)Ejdv+~d??Q;kG^?`T zCtH|p4>wrg%!8`;ZC#UB+gFnPVawoJNRdNE z)45>eYY{`CQllqz4v$+-C-dB{Tz|#acv)|=L()5~pa)M(H@Ui;DPwKLt^2=gWGP(37a1$sla| zgJ$VNbjRz`8hz;cGa9`beHEmF=DMlaJ|?ob+`dA#p<0b_256u29HF#mpw&{ucqFjcoZD@E-<>MdLC%#&THQ>9e?P3ervhhBQsK>dNC7#!{_?C zm*g=Y;KT>g)qcFAR(n)Mfsu?_-Wkk_>9GZ3X@1T8eF-A&-D2lB*?RW<+hl?(^w;U6 zO(LK5nj0!#!$GHn?~td5)|Bv>M**&3R0JY=-tS@lRg1Biq0nw74uLtxtjvee zu*!cF9jCkI<@l)G%>yAw6Kp2qchYxCep&JhC#-$o(bJa)Z#3p(5SRQyLL5v71sdYb z2wZP|rqf2N?y3I|Mehd7mx|}u>B;m$h;(nnGvgC_uXT^7)QoY30wmg$;vGY=lseRj zgOqW!YE)y*lPKw=hp-wKQ}#lScJk5UmpRrPxYyrDqPrmj@BnY$&j)W`&E40F)85T$ zn>eg*%&wT3PYOaUvm|YP6k*Q}wmPl9}?-M-BFg2ZpYznw-S`nqmfGT$jU&5^#pG~k`L)5I`2+@)ym zqS4)C=DbXn0r=tnl(6WGp`vzJka9n5aIQjmxfEOpz7T62L?=&I2K^`+n=CTxyRReO zvlRFE{OvdqT21xA&{d&#WluQ_Y|H1MoXWkmw(?D4Vr!6NQ17mX^q{e9-?iW2e3a)? zvvQoEUz&W(TkCyF(KXhPfTfdHrn>A7h4xe0)KHTA*@27VeEH5Wijc zd_5F}+_LV+61u~7Mo-z+oLd9$ix@k8FY|aX+^*17R{2vQ21qUA7CS-=auBPOr-N%- zb1eNZnPIs}CNcyNa<6i*Ps^Dcou^R}}Z`+p9ZkplXklz*_4R6$fUG)Kb(N zxzQISVX6|2@u5WRO{I9louZWWi{{If$Gsz|M9Ug8pEKBm`sFXBBpM*mbIW^cye3(~ zua`xmZ-MSTX1d-h;(D?Hyti6`h74#4a%28|c30#3_=P7FCG2H|E%Cqv{~=mC0Rx*= z(1tB8+@Gk_=$m5w69X8l9*9thHSLDzr*6GeuYQ#E{nU?=I;(OdOxU;=%zty&9B37A zmf1SnoDliGn1b3?ij^{{47+Z8Ddn16yG_<@GfP>whe7!_sVc{EvFlEk{wU{D=~T@E zT@HmOVMNUzy)K6YK7#m0cyqQc1|C$$s-$FrF;SgPC8}i#5Vj79wp-rwOP21}2%Q2P zb)3YK8R540#sKMZQo!bT!Mj!UsS1x5a9*o&>z2};3E{GU!bw*@@oB9ziEdXuXb?^F zMQN1(oGlFjzEm3f>7#$c&)cRC58~T$?)*a*ock60Hth(k;tGL>oot>J^d(AEP#f3( zwtYXkWEDFOYdHNngqHFNR;tp+F@ZjA3#Q>b$xbFB=rG%6r%C13`~%3UZjHo91p(Rq z1un_l;BjZeuGxbpH_2t42g?Ga8E&Hp{9p!>`0xx;+=$QpFyC|8YZk>rESJdL9L;pT{0Mb?IvOP3Ar~o30r12M1)H)0Abj zhCiTtrzI=hH7B$7eZ1h+rh|hC5B7dWB$7@|hgj}B3lMSzZ-0c_QGw*&ckMSGtT3OH zL{LGGKQ3+VvR;d#UrHC;T+~e*^IvH|iV*Kx1$I1>k>aK2h z#fwQGLbGq(qfM53vmN%*ZT8*HoWFC0^F^Tle17DM%*Mrk!QZfWFBSCCY71fVeH-jqyYB0SMK)_ zydlll?$whqjfHQtE3J*btIBtWYe9GsFW0e}u+mKCc)73SH}7;qwvSt#CX~qqcK;1Q z;!UNU)&Hx0R^c|C&S2)r*9?+})PN4SKzwkGup<+}hka!$_~2HMpf*td>@nIb@Bt%GSIY07818HplRmX@#W za4|4U3_-%g^`-UY7i2e$vd9?8!`e=>c(T+&&5T0DZ-{^1yFQ;kEbY~d8jz6s0+fqj zq|6hi?Noz0x@g}JZlV4bm9_HU2bN#7wG0S$zeZJK>*0KFXGGNa29Sd;K&8R00s=E@ z#ngLK(0j`iB^y3CzBPgWTCC<9e7xBLp-U)$Wi8Od_6)y}aXgWqEX@}MHoQ2mZIie% zS7cE1@jk^Qd7(jBX{V4*@*SWd+?ShLJW7Uu0woj-u}x;jiii8re)vwBb#Jz{FuF4j zRC`G|Pmcec$agjC!$%1vZGU9qyQO@77+;OL)xTr2)7HUR2XMY$ax=pkW@fp!Ngb9x zH-iv68!CV8`PuwWF-fxXE$K2QU zb%FT^8^P!Dn7!FP|0Q*0y#?%0=4TM!SnkV`u`iL1U+E;C*)HUpI~w_OqJ{RlTXquyN$O_;YPnR zRi(ejvC44$Eb86k^Q+=aXe|1Kes!t>BmXO~{`dDQhoKMWsRTK3Opd7Nw9L>3pB)F} z{wxy4X(nmiYTRhnY7-9$A7(FFTMGH}^v3$CPI=F_MB%{C|8-hvN027AO+J4pnXT!I zv*}d&9=tbGX9MR$;?)0fOaBt0WqZVtxc-6WqQJZ&^=@X!b1EZIo+@IAuR^#?kH;f zJ6o7_H-&%f@m&49>iy-MnlS-DJ}6vA=$Y{INWD$6mFv2{&zf=U#ms!ZtYLe1rCdJ> z&{^K3%~o#~tEBwY>Kpbi)~L1AKIpMHQlehP&sCdY{c>EbTZ6T{FAn=wJbk01eLsJ5 z%Hrfr=ksCTGi7cf1Y5)7h*f3mX4_=Okm;bxmBS)(;sAyTQ|LN4K`)=f{b+ zpC+)Kx$;2HZUB4&^oVbpy*B;+uG>PTud>FAO!oRST7nlQO04xOKun%jT_j`OKg=&;A)|?#2JF=`9pLKq}Vw;KzaSRv@~b~Fs8e+ zB_X0icaL)Tn-A}Y^{<`xb*Zha<7EAAuAY*3Rrr?X(djd+U%;`81mNZTK0v6Qd?qM^ zX=GxeSWoM>-5=ikO_hW2`@LFMIKVt)fO@W!mLB<{#lO$6-7lOzOmhDO*34%(z`OY7 z>MtT3%F1Hfj+?4CJ7wa`Js+5mxltnpauWWHhYw zx>vTh9(6sxUaNI=MvA1waV_@~;=-hW$UuC}OZgoHA2-;B4Zzf$J2Vo6ZGTimsBm0X z+VFp|ICz8br^zPnOy4#br{^X>P|Qq~_I^NwIPF7&g%QrC3L5^aMQkHGKSCU`!b&@N>pk&J2eEsb=T}Kb zIH7x>WRgW=Q10c^F%m%Fl4ppF;b=-238fa?EowR~d|+CqTT?{Eb^ULm*Yeq4k+NP8 z;%rI4*Sfttd)G9EI{+N=(|No>i)YVB<8rbj<+S0+0VsbfUPz-xEo$3ZYA_Dtn3>16#tfcn^on(IQ4=ruo}n5OHkjPrc@>ZanZ2Coa|w3GLUj zZQH*VIRx`ZiH5GgUFI-40gMYO{(tnZ+Xi{#aeqnE4%x z4Bfrm4~mc%j!iInJ4iuf5V2aqc|Vs z4F=716y-X`t4chDH=)#`9;zo@oFg%J8@Y!R#^L0yF9TnM><&#(9hd@Thk5}=>%!;C ze8s44jk4F1upbyWU58DT>+;ly6DeDBhSDv=QYqJ3nbG%%)Kb=57+NOYMtS zm2S61iz5pNZ!BwrLM`9hgeC6K1(pOD{6rSkS+>9Tv)Z1oEP8)dUgR><^j!FLK^B%R zkfqCqQPm-IF{ZS1&3WSJ?86o_(X`sgBA(KlH(&F|lb+~PQ!$y&%52A?8VT=Z9;A?m1VLb-sUQquoA^mnrwNqK`pSJT);W9n1 z=!-upx(#N){C1kc$#DVw)h4eOnfM{uROIXI{c*Fk_dL-9z;xA>GMU~MX{TyL}{ zyaVXN{X8)n{+&(K4BP10-=)i?yjC4&8;Q01w=ikh@ABwOlaN@oJ#3$YkDpGkM|aW_ zA6I>Xi%C@`fFY=7Z>szT(FJHBXsC`4)%M=&- zy=xD2yQ7nC-mLbXMR9h|Tpa)57f;BWoTbMW)*vzK!HUKR?-E@h4jZ&CzWtc*vpbu9f(m=< zbN9Kr0@SV1e>~3@7nF)ilvz0Ru>ai*wt$dKgKr^>$9{_TY&v-JcuCmSgdugvs?K2^ zdtACpNZCoaLot9YU?zAZRpJ+aCRT0j#$Mn)+uvHq*>j5_dNxTmU%F8@Q@y^Ks%LZ) zO)8O{74CB^de5`VLx*>*f44RatPEs9#&%B|KFPZ{6L7yk@4;02*okwb!;hVP(!RuJ#8-(Y3h10(Lp6 zLwuOSW>F%O!?wFzfMw0&DbSz6`30_DY#plrBdm{F{Wg4b<-WxGb*yFh$?;A48zMdr z;9Ve^&eqEd>R{cWM-CcKbxAKXT1JZ5{I{+*f|ZjqZ8;h{*;*5CGz5AhNPi`nI>m!X)-6F4rq4m?RXw_luaJ?^q*VU$vU%ChyBG_Wv;JD z#p@DN=>Z1+VW1x{LiZxYy_Nl&v#)W#IHLW@&!9~HacXKC|H})CZIh-`(!F$JN*msp zE7X;Hp%9+p^JAzzo1S4t!8?I_vV-QgqtgHu5j_VRr+rypSiJ&=h@pA8@fD`zjj8Wf zn4niNSuiC3>D*bc%mT1Z$aAiB3uqFUOSse-vwtBX%R%v`hfcvxtNu~;z!8sBRmkRq zuLG|MnT!sQeV7OdsXt8zw>vbNd@tpk&D&(5W3EFCr7MS(VXc z%vPR=-3h8fb%Gdt>OewT$;CG^thZ;vPX7E{^UkI)z?L7 zogH&I+rMGp{RIWS!=RNjbs<9x`CZo{PozPn%D?c zxD~idEha9tlf$g=HV3$lgch@btgp{&Rd_JK^tQ zML9RGppeduB6$#NF06JO&awaTQ@`)rctK{!O_dKwq`HG|EfON$UFdo3wD?(OEBdc+ zZwxi&&1fCI+d;%S^|2QfnvcBaaAVA*-Z~qxASQW8tw6b1a&??qVXp63{NUtYuv6+I zvBGKz5v0&XDVl|w^1Z*7c)apa$ow&ruzBno{=BEXqOFWv)2z|aM2@L~ zW*aqPWp-fMSHnjsXtYF*i*SbFu$|*d$X9G-d!gasg|%NV}NpEHf<46uoOL zK-WXN_T-R}Ta7?j zG~#GekHg;2Wdu$4y~7d-+BTaqYUs0_wO@ss>A}POkD6ptbzxkgP_gRXs}C)kjs;CY zHfhk^wxDELa`D8u7BAHOn8tXODXRTJyG??(8_lE=PcQG5qni|Zm{%*KpLLNWc=pKD zwD!GmeHV#q?W$rF`1{`Ac(%#LtS(+ryyM9naaPWw)I}9d& z^_0oI=abw_AM?ru?FvNNJ0KvAT3siPtL^EEXUKaWYyn;{CQ=srC>zmf6Z1e@bMYyE` z;$el5@BZvo1xf1`V&N!f)IBMmx+U{}Spb~sofZX6YK&;7^*1K9*eZRf#>z_}Xya=i zI(mHWY$_vpNnraw75vlKa0$W0A*YW)UG!zCC~5wDB^?nP#h~3h15kVAJ^hUq`4y%7 zuoLn2bRiwLm#I@(0*vfy;zx|Qe?ZoK$JsL|uMtKp<;d)KD^FR|lEfI{f2^ebluPU- zfKw*kXYM})Df;QAKy`{VPa|;Fh8yc6Is5n@l3&#w1M{>}1|3Ht z#c=IO_fCtU0{y*Ttmtd}u3(==FcrE|m8t{yk%{KGsl@C+ZFW7MsaH^>DQgtzPWhIuba$sBT?&#) zcXvsQv`9&Jmvl(S&^3TGNOun1HN)?Cch_}y@4dVC|KI1sABQt@=Dg=U&-=VjeZP;F z_s|mo(b6!=HInTKvp!GcObchjH0!}qpZBO!tDP1eu!%%-oYwPOA4#X+JT`m9-P+UnU%F#gmrrh!~6$NKTf5 z-;?f2MNph3O0bmRRW+pi^NgI0`W7-?OJ(BX4k9d!@qV?po4$wN=2mwRMI0SQ0Qu z4@djce6^LEMp$z8r;#U^<259=Oo!yj@PvYGKRAh1kWy;X6!_UkcHN{^cJ0xm(^eHV z3#LlJLQhs3iKZioUJZOr+;T=y%TdI?`}A-d-M6~Q^}04dcNc#xR(BQyEpQ3>+>P*v zb}i@OmNtH+vwhmC3$#EOcBmq6(4e#cTZwxIUefCFme%e>@thzQeD`*#JtPy1WQgIM zax$K~ztp^|+weu~I7LhtAzr@?+Endg;pk&+S3{sk>xX)6b#|Qc$Yi=y8F>vGG#5+0 zT>fC@H^J##Pu>Io79W-iB)%mV;evxz>c4rRUrvMLDkJ=1GT|#gKH$-0W zJ6&7K05Rq!$GBtg@kEx#Yl+}wQOFd=8m)G!XiibMN0F=`kDib~I$)H#Jwy}maMhYR zx`Ljqa@PnO-aRDRUj;i&+y!->2aui&wwf@owRI%5FiEYt@;_o762GA~6+xYwjC)cyB_KMl1gCYvX^Z>Mw_04bxPH^qz2 z-EB5um###Tq_)KFFbr%w&$br;VI`AV?*KkT1LY)|3~VrW%vM}*HkO;hWEZP$ZU{X< zlShCV4Xj4xWZS)iJSb{=Q)R*g^k|PB&er}!+8G=;&hYJmI_y2a7d&!8=JW$%2DMk0 zSQ;jy>$d65=eOZ=^rXsTh1^64SS}5h8k))X9tRG7OC$fzQ?HFusPRQ*3cOg_T7J1V z-)8deT=DM6xk9sY+8zkC@7eb@&|&_!QVCm@zdD~Ulo?2UKS6z4wWXn?2%RIfWR;y5 z^@TA)dR0UQil6PQR`gQsNFLrZ%$1^q^qf_gC47*NGFzuE3le-ISX$P>(J5qhakT0v_X`ETjm#|#8c~0byk(ua$uWz}X<2lNf6?%Ns6srS*}oY+ zBAx>o{qi{9?}6otNR;?mT{eDX90cbDgsk)++?ul?+ z9pf9W-bCvLpz}L-EKrRlZDdG?XM`I@#QW5K?fU6*XXuzoX@Cn*NRUBKb()Cy3mrEC z)u&=v^Ol6c2*m0j-)67QmGg{eJ2{nVWK^u3_0uD^Rr2IV+>k0+5mFN!E8&O59YF(#nQ=7QcTXE(0M*$E$T_(uhB47y$l{?e zN4-xQ%dgbc`{B2IFCB)$L?YS)D{kFPzY_M{6gYK)0xnz>gBF7<(Vg!P)*Rg&woC;% zCFU<$2-n7le4VGLv3~q3z4H5HKunw-!!Ir{_DGp?est~m@D|~fN*ZacT88Rot^Inq z)ogt)&^gTDs>)Jj9fwMmWQ2A!44Kg-__PYu=rF)Ok$-XmvWyL`%wF zrr(PNkz@w^fGYU*uY>+q*Q4K!AQiFcy^o3H=$Ghx_X zabd6Ce8c^Xb^Ny%|JM!_zn}5KLcrayr}@Ez{r3mW`jSA;rmp>r((g8kRTDLVLn*uh0#q5M!08E%GKvu-=aFkXmnJ(I3Ack|$j0EbA3Dt5dd{S!r z=O|yD{j}u8upG`!VTTg6+wXZvAT*SZ}LFbXrp@HJZuQs zFdxnmo2JH)oFHj*obQy2Bg*qgtkwyyu)2vUd|OGS2o22l+Y`2VsU4t~t)&Tx1Qv zY7$H2&a$i27|ypu&eJLYU*}H2vuZ&DDV4jG1*#=?X9Q<*VvFaZdM8Go6Y>37K3u#} zUy9zKf@`)P|JLo{JCA=FB2jCDWXvYgRE;5|VN~<5*)Z=Eff!KG$ zwwJR_-D`Wr&%!d~M?$T|VPrsvG+W_l)k9qU!-pb<{C4gkg;CpyUBTfrTQt}7V|%vC z#2dkKu&X{sFH16?b2YwllxJ~NlG2&^Xu0(=p~lshvE4I9XOnzb*H;L=wMXt9r-2Q+ zz?668h1I^NQ9^$lz1PO~4q_WZ2;V?|_yFa7^VA8UK}##8VzwfZYw_#AThbqd)YBdb z7|*#+R`0z(-a9%Vhq?eHc?Oq#>WWQPI}+n}RjysI-uK+F>QirY9&b#kCp6409GH9) zwLYL>`dU`c%! zlbA^j@qk7%F{a<(pkeY52%?f2va6lxi!6LQz)_)x#JKhxN^lQ^5OQa|8Bj0)(m1`z z)6P#TuK?kANz7z9#eu0D7sh8iaG@-I!=e&OB=}M3FJeIE)fEhMuM3+*(zX9t)_*-F zV?)(pc3x&PlC*9R5P#~mA2;8ySwn@X#4h}xzBl7XkD4EsdP}~iI`ct^6#Kn}Tyv!S z!cw+Ox$Ou(z|WNRw#iA8&8UwIsKt$ujc29)R7Wh@4N?rD4VbJ z#e-I(%bBGTM)Qj7inSW^hj*g@O)s7Ft&CE&nCQ@A@%aN`@ReZ79aF+X3suMM$$AB# z2Rnt|y|q|@T6=X%mK2`=jNaO#bxQS!tO$N*d7NzrfulY3qS-i>XFyvQ<`Si(T%7%H zW%kwippuye$2Sw&EFhs;+oPOqV0k{El%@GLJyiqLJoUI%=Gp;+rO>Rau)A)Tx`6IQ zM*xh>d1`RHNZD)MGQb?E%`6rLy5_FtY zq2t41!&MdZoOQLv-|ev~Rb%~f(R8)pK#GUm{@@c{$E^y3m(Q1o6pSa9xm60)RAPWG zLJ%v?xqc!YF<%$iH|0iO3pt~A4yff*hV2!$qG(Szug|vCc?%!LUp+9i21uM|mFg+v z5=P&Ffdb0JMwF)Oo7pC2r zTYjSeS|xw_vi?=Z%<<+K%G<$!tCgt}=p~%bp*#J4sMEtFH-gcJP zRI-<2%QLp{KTbzu8ng`(Tq&uO^InmLi3Mz-r4cRLn!TFU)`Rx-%?LdnvHdJ zsFesMiDbWl(|3t7a3#GyE6(Gud{PyI0_bGN5|h^{`8D#dPjVHE%hLdO$Or z(M22Z_l=j=^|YKq8cV^>K$ezS@T#Ic zbhVJ&eyvrR*Ja6@LWW5D&`5?pwq!OU+x!dyyTZ(JnnbYMYr4uWj5LD>J;}aj@M>W0 z#sCUeDz{n(Y$5K@m4R@1>9yW%)w78`J|^cq7&Vf8PVBj@9zSH-Q8t3wQyLQ6O-UO` zRSMzvfae!ZIjMyvfhl;|v!e*mj8!c?ARnDii1_WLSosPrJyrBRgKEpOA`tRJO!3%N zosUj6bHV9yAS(fy+^^c<(%E+WtF?Bp82S3;1=9`|;LS3I;0`28rF)1aP^Ep z=9At75fqIQdB#WA7dDLO$*hjvff3f=D=qxIDu;J_mXzK6)R8&YS<9cgP>x}SL-3+A zj&)M;kf^d{>K+J4<;_Wp4-%60jddL5OHXaqHU#u#Fe$tIKB?8Ie` zALe4!k-xzmTr!IsOy(tmXU6QB5yn6D8@ z1lKeBqel>EyUdXk`o1_bY|YAJI}Tz_ZngDx%LC1aouquD8W!@Ls$os(BXuM^aC2-B{>o_hcX*+hA=yy32C2SNCwEQC{=-#9FN>^muntZk-k6f3s(< z{`r(2l&NX%y0^o<8nz0OYVu0W6Qj-sc+IREU|=aTV&UC`@P@gx6vy2HJg|{vyt~2{2Kv@!do>pDGVVObSzVwSzDl#t2e^>-`E@q@Zw`B7 z5-~Ryv9xo17{s`6_F-wF7XuzAvghzv&S6mBFiWZy~3dG z&GkOO$H?_eKCc7GNwvvc_tB-+2}=;tw&^xJr!lv?GO^n5?VdQB#bIjsPBX1rg*$xC zeE72>_9G6fcz3}OTT40b*HSo;EYFb2PjkMDF3aPZkN8Y$^;WNibcT;DwbeCLnA6u1 z2F3Ix6tpWYtFG%Y6dOmv>NL9}sa&7l)~>-z#E`yHFxIf;dkJ&ZV2pS;)>y2CqTA~7 ziwpk42|=O6I+ZanA@cZx>8*o(4y?Z^OfSZY!t_l6+r!t4=({(YI<8u#cE<(BUWbvRSi>N zj?o=eTOQ#vL=+3YgYw;@2|1^WrZY)LLBtG-Wg1yL73S0`$nh)05_l#FrBn0Eq42%1 zIWe24Fm{9nbb@y7hBy)-)?;ZINv6u1Ysn|Vzu>Rc_dk44(jq9PM|Pf#$u> zU7?xp{tx3c*c3Ho?sco1NkT?HR;lQF)S}TfIjxD!1LP}-iTrgQWE=)8sggphX784Y zO?JcXQfw6sZ9%MCVUM6#DIyzJ!$H}Up~E`9Tvti8M~-hW=;T%d^(E;0`(C#A($1?= zQ8hwY?bm|e*>;vKcNz9io$x&l;#`QJlFJA?70&Dm9+NHmoOOIOKx;YmWxU3x*?qH> z7op#C*+1l58gOF@70P&SPatS)FI-(63a@(ZU1^+K3FymN;-}04+7OMGIs@zd*1i`& z$-WJAQidgnb?4eLovGU zQWaNAc&543j?usTB2d(?f+`F;q>8`DI&g42QpZ>->wQxr42kwoS2gb2(|>~ANu2Ub z4RHjhezSaqgx0`P?XW!~m!lA$R@mmN;Sis{CKn8XQ?dW+zjtWQEqVNC<8-wk4DzlQpm{YdBi$`fRUyM+9@5hKs33nBs* z9-S{+vzb+iO2Xb{8%L|S81cgQC?5$q`Y~uVN|+Ca?aU6E^?VgIu3#aZI$f1ni3&E2 zfGjDy8C-PUDR-Thdc<~s*@)5%!CC??G~B!#bC*h`3yflllB=R+bf56!!djbGetbEr z5j7HovR3?!mcE)K;!$rEP5*_3V)a`Z(8S?va`iU199h~;jU!UgrjY5P`0VM|n=9os zRAHw%zQ)0{%b<&uis6JCJ;*&?=Zm`I$CZ*sn5L$9sPqW;M>FmmV-|;N#JwbwcxNcL zkaAt+lzN@XaV`9)QH@Ef_DOPL%$Vuho3uTf%3j=0%aDApp@uH+fN>Zx8n!k~lxBWY zl&aM%n0op3G)4*!bIDl}!%eWO>Vx*&95B7opX>~zOQJhJ>l-2L&l=eo9IlOCkvfIS zK{<+BeyR?hC;=KA_9%HCv{*UEpacP}Z7L64tH!3`E&l?5P6B;ny7xiFc(J->id$X- zzLDI8X-Eozcd5s{EV&rQh&?>COp~^rs!V zLG9BkyIFh`QJ_-XsIoWGc!fLD0T*#mUmR2Yd z_c*1a%V0miug8ZRQA}8lB$ohnfymP9!f8M5r1$OS`0Aa;jYXI8>vmyIQ36NeG*E>SM+%{tHJ3Q-+eVUF~9k=88HFib{C#{C1sjY z1w<(tKia@b-|P5ZkT%?eR;Vm@pzM@cq$&Cx9-g|9Ziw9-RCL_AL$@CtnA_Qm$OjkQ zxSvkgiCp0;$U8c*>T`Bd$!YpAuZT9S2<r)loelhsukpP8y? z%5f0k4a(?~jnfWSLe<^FWvwlKoll|PiH6YO6{#aJ4^Otnzc*yutO~n!iW;x!;%t6O z!f^M}c+8Bl8(s63K8MdMGDJ|oXlpFs3FWbe&zeo&-S^@uFEDlW6;%to3^_qZIi*)E z$Uf@3aP(@p8YiqH(!Oaj&2qh~ogmPWm2MTy)IPusJUty{ya@Kn&J|5V#rfx7J;|3&uQ z6*k((LF>3r+z7B@hz2qP%lVeO;Ub#-%!Hb+H!t2AT(bnV&?c=(jf35O>V^5UH=30^ znQ~XvhO?LV4_CXb4UV~QM*6$(S;XVCo2)E1hfYLu84;(dO##Qaa~L3pJt2U!qOZv? zc-mG5V|Uv>LaXjuN-~Y?bR&i z3b}Pt@#0IjFStae_1w0I24y%Th>$;q;j%p0@B!&#SctF+f+ZyjsW8ZA9s%}3p(D~y zyJ{>5z*u5R0BUDGj7oRIeqP=bSjnjE!C#Y&=YI}VxKj_pGBE+{ zLwBIyT)G&h^YJ%ZkK>a8e&V@O#73%thx6ZrWE zSKJi$T7JFzIheAK+pyAl8dCHU`8hU^Nej?vZiHe&0;OTGl#DEgz3MtFsy&Q!p7v3pM6&_U46rHn2xjwQs;(J!W%xGTs2ln{xvrkS zX?|u(&0jUA)@aoz)RoE!B|3BOI9zSD7<+#Xa1*Mxx+jUcf!EAKS$#ZOVUEdBrE_X2 zEUv6EZ#b><75ZH|q+S&J2~Q9?w&eRkGoA!nnrycbzYHRKI)bFplv}pC_f~grx(zJ6 z!- zG}?#FbGC-y%G7p<__m&l5qQZcGLd|h?%xiGT}bn+ox6(tx)ti%iWQCcLhH!)9;8{8zVwPI3p2+ zCJ4+NRdLDyKqm_Sm@8=hPN&CAT?1vGgjz>Ltz1-6MLg_gUI9af#(IK&hoVnnDbB3; zBF*-ZCF-qpdzJ0xC&5>xQje&0g&r`d)%H$lEj0Qw13%VIDfLj>44g!&rCz&QDs+hX zQ)CwKm*2AkL23S@g-1V~eouffI67VD5wJb&ECPi1@;UcQ=b2}KGTz1&bV6lu)YqEC zed28`EBjN9geM@kgnH-QjS(0!#*|Ox{6tj?kO=If&y^%m`GS5`N5Fhp*r#2imdg%G zdxm-&1#yUel%%a26Iu7zKP0iTN!-!6B_G4#!pGy&;>(zVoF=Jz?A`Y3j4Zjjp{v@o zgyJq{3M=$zZY0N(W6$>W022B2HWVJYB-n=?1+7`~#X%)1^Ss0V#&cZ2`veW=`KUi+OnIGODXj2cqG{k~FQ-M6pqP_}=FB zW$UbP2$e`~X1zb%^aC_-rJMyJKc zqcDNT!u1xi{VKeUU@QiC_ifLE4lyusQU8Ug%g2kSPbXSa&8?>FwJn899jBdI1U~q^ z1|Ts23ZZ&yBZz=G!64iTJ|7B;aGPu=tY*S1X#3)qQAW=E?6RFP z9C+zdxFcmgBn*gF%$CeHFjnu)M7r2|+!&~`7=ODg&yvf5inz&6<_v!;)0b9JCcSji zik}Op_k@O0I+SRRyAJvE1aLK;DhgS)-VFAjQGMG~OE+N3wNKjScajfCXDp~98M@gC z-2J?Ryl{$G8rPzQ0sDhW-p_il51VL-lztEUk)#BiLX_BBh^oS&i8SQkORAX)FqLFx zUu}IIkhg)7q4)}Kau0G&@o{UkpzK#$VtKYavmc6-**3Z{FyY}+Y{ibFOyLHFQx0mE znv^l+WU!&_o$UTTz8k=M}UaT)Jv%1WU;jIIjW)VEexu~z0YC-4=27^-P)~Hq&yyiQ;WVko8So? zevUC}xX)q*^eMH%b3It1l!|Bb(~5fEEK=-OGBNY|-ZRS^1!S};MHgJA!OPhYM*I0p zQXuGgDkQvpHKN6R?Nx5WNZnvxf0B6H$N!yNs2?lV27q&s$?eT4lzuUKarL&-!z!sB z8d|fTVoL=o4UOaLPuXWN4FevjiJ(~hl`*qs?6c*V9tUo;TZKTo%;HviZYc`G^3s6| z3RGehgimnKZudQ=lKN6yDIyj1ZCfMecWRV2>uHZLjkmlvJ(k)081AyHpXzsVNS)+S zdwEXb>aJ^%4+`hvV>(=zr8M$T-_Ryj-pWNu`9l^`go9ed%aeoj*0#{^+V1?h&P+RP z3`>(Q+ieWpx8Md>3VnZcHjg!iM(R4|)o&v;_Y|-Rs6&@ea5d__8Ba&DZ({9PPXq2j zQP4?NWk@$6caq!|6nzV`4-ByS>?{H)HIrxbr}zBXsV+_eV}&P*c{vsv#`esH=PPRv z6$DowXAQs%b(z~omJr+?YhRa*g8MofVMhE?Q8eMa_w5--p4K$(v~i+_1)48*CLs8> zq|D6LpA~-QVWP^z#%7>WpjL;WfK&CYR4!rrmw7b)cioCQM}&)rSQS` zwD(5>=KQtAV~8Gv)%2>9ziPDQO#Fv}q6dAOJVI(C#l{E7)|KM*0@`@mR5<5|d@t0_ z??4G!?ABbNQ2R$gHo-xgizL4IH*F5z3W%vr(l0PZcE#-6v<71-lSK<)bD*>ArRmIL z@NV~;Cif>^sBjDEHetEL7ZKHqSYeuyQDp7~D6B6yAsw}7_EJj+qth@fdZTZ3GkA#d zowN1p7n7zHn>Ya$N;-#e%Ss1J4@(?_ai$NfUIL-8JoTLSc)MGyn{V4(<^PaJ8%hS! zSVJC&r8mE;n}s{KzmPKfj(;Z`fY`3hf019u=4DL)v!u>8Y(jXJ14XiU)Wl4bOJr>3z3+2g<7XM z*=C~`Y5TPCQy_toF8;xrMcXW4Da?E9{=?68(eLK_8qc;0hDh23U$0YcXzgm^i)(BwApWDwL5QtOe-^8lVC=q7KYU0(-; z6`*8l=kIGhY62V?V@l3@^RFf*N0N6V`xC1-Yr3y-wlD9*(?9(Jf=3Zs;LmM+&BFiM z@=S8R!d5gFx=TyyyH~no3uJvfm|dmUWonuR3>oNHFz|u))n85Ji!#ez>mvyuDtwit zt&H&;GG>!Xd`#I^WV@V#17Ik8WhAO%`?x|*aEzG)5{2ogx)Yd2GaxNE1c3XoOCUrf zw8~PMN)L2=sgGxDY^#%+iVDouWbC@$vp1spQ=ITqvobzP*iVT8G7YTvRLPS##Lv0v zeX965EPPf=Re6Xw7IwTv6jqUkfeH|I=n_7&Ce3dM#{WMPYaJ@ITp!F$o+=#Q|pdMgW)M0p5**u%rNK5HLf92*IcyMF!7>b?O zjsiCBzfexh3X@d#TI-MOee&67!DC>~!zw7A*E|#>;Ff^t@XId)v=P*?K-7AphFQY1 zAguIScjjn-7g2~Fu0abbdYkQ|%>Zi%3_V^Zh0HV+wCP2nM&@kjT)}rRp&EtfP*P22 z0La~j;u!LNva-KL0MiNP)rZ%z9mdp~6XC99*|=DM#)W2m()!rPwu$ko4WJV_TDND& zdd%-xey%^evORgE3pqKf4Ys7!k-LR)6v@xMygs?>P0q>SJU&`?Z7RcsRG&~Xa-$Tpx9z{cy$o77YNtm_`2HT^)_W> zmT6Z_p4E<dg(-59oni)m@@OZbFo_?gcLit`o5d7l&y`V$bD>{Nw? ze+FkS)9gE5P2&pP4Fc_aj~r(xhjoQzQCRp%7lVz+Mg8-wU=vNo1g>#0Ah&VswI$@B zS+Sq{z_$qo55O+!G>0FqLNxFn3T+H)>iEy>dL}o$w0`AP3g8c>GAo*{=?zb8cN>r{ zO(vQLicjJG{sP6=mni8uL%8FCL2I^>hE7UkxL5q3?g5j%y!I!XPdhc0oU`1QaUWRlM?y|C}x#Z(6gY7yF`RZ=c z(t%{XQEnE&7#Eh0KYC;~mo5m3pMIphZbb@IDWtn)ERL?%Gb)D9|Xo~_{%nF%~?NQs)^+fViRXw|Gln`aa zwp2{G@&KusWxEXv2)^O#obm=a_3YEqC*cbxH9Ba{J-Q6qwQC{T%$`DX_1F~}&XL}# znV*BXSJi0n-de`@$nDuYQuSbpMEyA`AW6oD{Q+p$(F>0FDK&YnaEodYXlqFR9RrBf z04u7n4Z^3TAmp|lYgI&<0(#nRfm*EW0KZxL-PtxBkY&v8pHls-C@PK1Oof%wTv&~r z^9(=`NlvFx&TKYT8@_)KEJCB5XC~)W#dxZ8V|?R=$7p_bR}cq zE@qgQrbOzU z!53)fkyKK2SS(LG0FI7|)w{W}TJpo$GV~s9XHg25_eU?rUu#l}-6K%k38qf0w)%oE z_Z>P{0$tCR4tq8E#jxzO!5Tou?M`RQ#2W4vzFZ9N>LYntijo1;!LWHQ;d)qqeN!qK zM!v1ys6WBfIM|tLyP5vDq=kidK35gfbZl2n5P7tCUhN(M9T`h)quYR%xz=Z;0)Mb) zv0vl0p6Met3tx=RbLP)gn5Fg7cn~y1Z<}b#sjE|t@KuFk29yf3iD%5Vki$q!u$qr?hDJ&Y!MO{|3yI(tS!fm@>~Ncykj-r z{YSF7a*xd|!QX*bxjU*H{4{GSiuDCj{oZ zaWZdl^af5{+on-CcBUuZ$&25VYfv%GkbQ}@j$KDHQXXg0>mG;Yu8h{wM+hl@#tSd+ zuu~I@c7yWMMhgd3wI2;swIS%9R^3UT4pc);y``|aek3_-=eM#xUkxdx1wqa)pxH0L zeRi;MV)e2f-FUJgr2~U*w=qhm!Z@L`^E?+@gTZO#?Acs)gW0e8iuq$VSq?205p3!R zKu_7iN|UAC#vAv4v#$1GJN$gFbhUq8Z%HWbg9n;#w9 zmcDkpL=az|*$J^)>cf7#kCh`Lf`t6!41g?}>f#|r0p?t+LsetZ9n)#(eP}O%D6;x< z6%%&RILv48bJlsOIpf2PIzb01v?51@lUyKS-U&S_)A71ybGyXN6?)E+!lz7kaTxSO zaV?v`K^?$q+0n6!%OcCzJA8ai?N!QR_^l)owT)GtsOzx~%Ez5zpz=V4|4Et`3#)t* z51-Wbw=%=lu*_`7-nC1j1FX41^?EHdbCwtl4s$(b`M2=^6|*|pQj0-*X^Uc`243zl zI7vi}$8jl4BZ$bGF3!Kp3FBcKmS_Jju%O*C8c@6o9nCXuL^c;4;a)bxOQ$!eCBf_y zBSdmFyq)*36CRGhsIGs7juqMlv--lHeef@vX;NU0d`&8Mv1anLzm_+_Mmv;cM{qCp z5d!@Z`@YCnXqaOXG!=-Gqaudcj1{P$ezEKb%1#}zJ-@TqRNzB~ z!6e>2q|{(ulWTu<&7s>z)5xPcvc~uh+!p7RjnwCA?WdMj8jDkCt_yK+?k`Zu%OW6; z=ct(jN^-DF^v@L0(iZ?wh;>GCXtDm}oNBJGmOMh9=mKrW5jF(ES#t&1U^y%#`aojk=z%1lNZTe?G3_HYe= zWUY1(BvofM6A7Bmoav=x$AMzur}ZhMWHSn>Lc|}3i(j@NjMsF&4Yajhhwj<)+Gf09 zGru%wdCtJ2HrdR+&>50gmtsZgk=Az5HPd7}mQfn~i1_GPXl`oNQlqP^mbK~jj9YaP zjkf1YC9+T89FEJ_;#qo@+n4~&=6Ks2sGpAR%_S}yJW@PHL+l*Ps#NABE zT&$Gr&8q}Ge%^)o(Vnp_`<}<8ndwQxc}B>}*QL_^J1I@@N+q%(c$ILKapS1q13et-@vDs%@HDwz^$a}8Eg4y>=PXy%{f`7MF z>zMh(%3yk%#!K`ND3IPXyYK9La(9@k;hrer(M;`;2H}uZ)tn|V6}m2ni+NuPq)EnbUDTEpuz$W?YahWWVfbDIJ2%JL->W^p}{Dg>}D4Tz(!l3Q30>_9Un;bp@>}oTg>@ zsb6PGgvlh;*ir;7;n5p-iL=}T(mjo+_urxn@8q=myaF>D&eS_Au!CKXVhmKgFDay2 zLy@&1u1UjhYweUVNcgf4LmnM_6KYT4Pfh@k3_?3uP3YCuTq`~ac09;^Gt4}pJ6{-( z#7axA6nz=LWomgkucP}dDF=)FuX0kl^>iW5&h1XzE=Du2k5E&B@)UDWoY8go2?S(V zRX$Psm5VHX)dahX+47{z?&n5SJekg~$vIlD4Q_~YD_cN2x}9P_M^tgF@EQ6^(2dKw z$NRzAo}anh%CVSK3=Md^Pa&!q#(w+pGEg%S(K}%!HMebwn6Ng~qgj)&mdG9pJkEIp zuO(Yk#bKju-8)#-wy>xCQhO-nBSq@)l|Y=&XZ+T@5C3RC4<&y0cdstLoc-$W?!UlE z6S)ZlH-uH#0};sagzh~D6K3K$6T;Cd5gH8u%WqlSV4r)IrHt04)&8u=*YDR7O%Ys5 zo1@cN6Kb`vj99ufqj|8sf@N46@$)<0U9!JB(?AtH!)@>r;j-8m;(wtPN3r$pFe8WpP9&s#YtE3o6Lk>>K0a>xkN+owug>?t@skDpk`5sH{IjVv#MC% z&qC$UM>VI@zg+-deMug7KZHIHY; zE+5B{QnvIXEPuc=g3P$0WdUZC8R$&l9sTV%xOR<8-dz1dzvoxN9(?P9W_R*~<9`&Z z{`DY(0jRpq+|Jf-`+2V-!S}j@j3G5J2P@oyL^F~TPgR$Fg`H4HM@bsTvsuq7L&eqE&i3}#FlLVZGy8~PO`Wdq!{B1HU$1q_7qy&hsl0bs_T;`suPz9R+> z4IF$MT~-i*cs|u&ei$KlF)qL!18Gte*K7ZPo$l1K4ZpmfxHA7`edY4RJc3nUyeEP3 z%lEoT#awB;^z!)lpZsN@mhR`jg&r~y02yRUJc;&WUbzuz2A%KtJ^T4(|MmElzepd= zh$2_iAAj)YAOFj72KM*)9O^Jq{dqqBFrdF)gYo^Eua$Z-|HC!^e;>q*|DQL+|ChJ- z|1SrCdda}{`t~ZjWF$vE8bF9?^!Ee(Qvhm>e!jCc^)E&t7PEC7(hr2S+)c+DY8~bO zlxO|P|Nlcy;$Pw||M2O8Ejd;;(xuzkcDUtqm8-$K z#a5(ve&^6G7xDji%fHTC^RhJA>GBkd^$sMNIt*~jxy{E16iaoURrjp-Uya>kP8+s3 zdwMO=`li~dr>@d`wLK8WZfle_nfuM@Hjwth?kNr}wi?)-wcEXRB~IcrSLunOjZ9Kq zC*-mibj+4cmcEBeLn9W1@7Qmato?Fxq5yc{0V-kl0!ngBY1 zpQU8UB+9=#-Cm5kOMRb^Ga^iQm$FQ+qkO6OZSB)k45E!8?^~DbI?W<^Z?iuFjN$+R z81r7!4OoZu{p^#0{YCODk1HpY{Uu5nO8d1wpdLPv%Q6B}Xd??BE6M3z7wQ&tx;phc zobgw%C$LMCL9jpMX*urB2if%-`TWh^d<%e`_P~Hv>ylL#lZEs(1_ye*)&c-%FLJpn zbaNzD%Tpa-2hhowA!$TC3SYb$$}}iTd?%|5(3v{X_elug6EnmK&r^(b0mPH8xNGFM zD|Y!Ew`iypQXC-F07tFqc!lXhU2u;+!5Y6IIXzewyi)E81-o_%qw*|w26D#AJPiDnle#sDQsC;feZ z2j_ZDzz>ZeoHRNHoK?2+-do;bVMn46N_OKq8sQl1-?J6p@I)}XIP?F!Q@Nz`G_K1hJ z(RidLTO+@Num19U-`B1PE;*KAlU189JogT=$qbgr-sBgF!DkQq-9De6+_iVkhpcy>uViDO~=62lr-bi&xntV-$SdcUTtTwzpx4m>< z>w6?`2o-@p`4wpUS@PC%7!PWOUhkyQ53}~)9eA0@lf8aN+#y0C6C;~8Yc*q$NOd*C zYcE^MVfIZ@uL}b-i_mungp$&)ShFpg-ks3Jv+CDb%vO!jp&9L4&(;|xPYYr#5bAjEHu*Gvp+uPyg-d z_GDXo_UrN6+ZYHA_57aKHSVXAWHN;FBM8M1vY;k$$viv#!16C$gG(4VWm4<$-G*WtVuRL4?v~ViaflJjB`1M z2(%#r@VqNU)pHSO>!O^?*vO3M6`R9731bCvieVDY-g`V+40rl2FN||x+j1=c(SM{H zMEbqvxz$qXt>&6h)8U6D3SEiZ)*5T49+0#LPr~XwFA`G!hcO~hf8Xs`_1Zsm$~~3= z$ay)ufbu0t2yVK@LC9my!@xe@0~`ij&%E`NNUox3$sWaQ3agnKI}Jt*8lYG=6>`9d z-FJ!k_&6`RA>GUv;8dglU`5_SjA|^}e4z7mJZpi#2b64DydZeeYPH+fWPWqu%4-F| zlPC(=xWNZo)t1xpDa^12yuGhJ$G?Hxf7(p`>W}?$Cd^+X3V-8{dZpPIqZeG8UPTR8 ziN^j6U<<7LD(DKtk~5JusK9TkcO$43NbKnXFiFd=TMoBp%Gw?jiki%2N+?jvo%jixlHh}5FWkCOcM<1i~WxQm5!NE$nr|7cMbXlAjms?A~6@D>%YI6BE>i;LP zB_T&(CC#it9E}3D6O$dMi9SG&Mt#$gol86h;)g6+9u;WaPgrgMLW1NaAKP+(J*FVe z6|yI3ErlUy7(SJ@dG@SdW)K1{UV3!|o=9s6V>=t7Lu< zja&jpI7MJ&HzFkq_v0P;z^5(|yfXL&zG&+MGP&}^tCd?NJ!9sohJb$_a|({8X}@ER z2-twtRmcz7TuLqGt2Cvf7-(-&c*$|7g3saz#45~YHFD&W^|JF0G#pJws)}&wUaOg3 zlJdH%t$nscI|VpLp;0-)a=Z0fxBpbd{-1ZS<~H*E7bwS1KKb(kyrqj;E(c;|X#I_g z!MU;n`j}U#IdUUCFFUCl-QK8c0W7CwiHFrspDxh8tttJ!FfoX1OuBEt7V!&Bwk9`_ zrW>x@aaQo~+TKWRSi{+Fy~;Olq@(02bd%YfkZT^JU_9$Hz_bEts&=R~M>CL?JFoYB z4h|)MPw4(9nf>+r{zL2!Y*c5w*OiHG{_4xQ$G7hNHQs^2@E)2bBKH1bG= zvt^?{WEr%)l4}KcIv^{wN|Z`#eN>X9BRMkEf`GB)xHal{PXVAV9&rVh&Ppt=eYVZw zQ~AX;3T?1Eo6SP5cgLOoWf_KkCxZ~I+afJVVAiao0O|m-8AzHvPsDGLsuv+%vK!0y z9xPJ>;8%`_4x^9rv3vt5g7g8=@z;IQHL3Eb$BXdmBZbZVHNq*($P1R_y`I@RM;RTX zo8i@70BS5PmCP3cteKn?<8vEl zfYuoFD2{`tF^m>tY1D^zaA*JgQ$Hz+KYjEd{(ZIF`3re;W>Ri10Nh>#hB+14JyziX z!5b1dOfyo_n;;)o7WpvWT+RGy2K)td|HGU5aUiJy!0?4l1)0an#n38s+ulVhBuJsk*4%K|n*%QsG7&#d4gsW`pE1(^dGY-6_KASOIp11*@}D=1pNI9Y;}>^s(;a6n z(z4wDA7)_z7##Qx3g-VJ36D`;rjy=R@G|{3Px~L<57}*GU~t4DF8_Rs5kVLdd4CUP z;&M;+&i^nAJiy@gZncX355n`|E&^@l6Kwc!sczd{P_FB5#7yuJL^_qi^Hi|#9MRv6 z;Jr0MQufnbf{Nny?nj?kOrpKI{y3hZkcKl^Ykv&Aby!@5O>GlIjMMM_%)aQR= z+ek$ND_iQMhjsSH>al&077ydW9{TU%CxVLuDCLi&7?I+CbBiB8Oko296#31i$7zH8 z-%Q5u^58{71?Ul6VInGk>FV#)$FE;lxCEO0!B4KXUDtoV`CpXupFVme3y2DhCy(sU z>_UH)j-SsopL`cD=-K4a*MF`^GU9+4e|2pW$MMhS02&KiGqDG>k^ARz{DSqnUOZo9 zG5ynn{+E9zn1O3b=8XsV|4Ik+`z!gQviqP1Y<3a{ZMwt%^!2<)EY=3D0or<|IRCU@ z{>!+&e}vWXedAgRXv_MsK>k+gylp~Mr1E=n<2k*zRc|TrfFVzlFh-%&{NVZD-0Wvz zSr8|aqB(wpuD%;{>SAA?`I}iR$mfBNDs{Dy0Fra6QYl-`%?FaG8cY7q7}bFHB_$t}0L>vBi^PojKr@^ipzwl2 z2o%n!4VEPaxM_N2$_;v6hZ6C=2D@_?*sVhHaA_4?k`*AxsufQ`!|kYR_|h?ShP1~e z0L9T`ZnLbkw?*n-V&3UrpHny{0v%Of$;2|e0@|Ibte-R^qQCyETo6-t^tC=>)Z?vn zAZ#gUKzYJAg|%AH8jheWy)Jd{?>3oVwt0Flirm4b4C7VnDc8RJ;C4h0+2f{+=w4Jx zAmFMzU-V}E$WH7du5t;wyO?sJT2F53O=}>4X?koZv}?Hjbv|O0vGJgjhg0kgacS?_ zJgCHIAR+s^S)Mvic162Ojo<}@zCIILH?WRJpX~|j)b7kTrQY)hy8Dmp)QoVE2&D~B zoo7=kb6)Rva~Gg@NtovGytd9974o>Ocx6{@G4!1A4fr`8-D{e>`J938VSf#|1OYLR zlQBAFAR3km&)8`PSOggiJ%PyLSSH^N5*q$%c4N=aF^rn|fa8+6Tbo-~*CZZdB6H~& zo&t2g_>A2aPypltK5KJX2O92V=(hQ9rGntExU=L6cI)@RQ1Aa^>@9=h>b7-Z+%0$@ zNPqt-#0ELc%dFXZBfqD#By{%mrY>p|1POr|wQ%0EfEO?PSLvn_|+MKY2JvkZpb&(64qM*va9W)&Hng(wAes>ynXFetJ>9L2^T7&lBe=7)xh9Vt8Jnd>V;1 zr&}8N75mpjP5tG$BVJiBgM8xaB02C8v;PE; z`ts-e#aRHNm{oeThzJPRuFTpd_>W${c&T^T!1tl^!5!-Q7DVTA7Q_Kj{pS47Ntv%) zjFFK%#?Q@wx~~E;cI96FJ2xrp`no_Av2H4dA?Z940*dI?DAOv^14fo6aI|%hf8~C+ zE7a`j0oGGN?b6zp9#NxrOq=pj7UTP$C6~2M!yKVcGTUQm>SQb$y+?rUPV;XXuQi5l z{RdVrh^Y_jugSD*F+VN%PrDM=@n0WM2mUpVl#mQAzs3!Bff zGaCQ}id1tBANl8s`GuLyBPj)pR-1NgYuP>kXQyIP5&=G<;53>QN#nCo60m&q^)TrU zy!%XcuZHnY0pnptY{p5J7b?V-0y4Xb`b_+j5!Q1K0MRRE)9)U@d%Mv1G3j1<_j|t_ zP6hDF`=Lv(7z-q=26$Jj-gnnt2TohbjeAUH3D%^U3%f~(iZO~IfQ?HPz&@AKf9A;L zOZb}Sj4JVe*rZVD4b5K=w7; ziUOcV8yDU7#(%hK{qH$=|I-!Hjm3l=Awe9Mai_t|JV*{v#tYR78u)s(^T%c^^+E}S zbk;e~AJnRv&ZEg5C#es>@wJa{9A-yZE-5$+^5x@bi(;2;zeks3)!XX2#stXfmKtbg zgS{7O3mgjdNLw7{jC3n?G{u*jDjbPLSpz;jbdG2+8`Ei$3Toj&T z;Id)S<5H7mMr_w)Kg}TU@y|QmU+*=qzUqB#aav@Uhg+=Pe@}Yd!M4Ra^>@*(qx>J# z{}V_J8VsL}+GfYwCFe9QPcuJZEJ0b4IPFDsSnG^ay#*j<7I3?y?`i%41h#aJno+xu81v4@4C-8s%J0LnFZSN+i|lWNn+b zSw)2P$VA{$^TRg$wn1d_cRBp}T)JgiuXGLaB=hY$xM!n+S?&Tlr(~;4?!GG}0WEJ` zGrOeWN770xi{)(@5?J;%4pp$A_HD}+2BGyrBN_jUs6gTDP*MVgj zFx?hFC;oJQm~Pbm;X4(80jD7>2v6oykq_nqbU4jA-{bE=&4b? z%L{r86ogj(`E?z zrb%sg2R!<&;T!AK>6ARX&^a|Wlyb45tTvb)68F`sy0cf8&kS&@$sY_Uz~WQ1R{wuv?4R z;L-Zi*-?o~(9GB)f<*m|c2%y^$G{(R;W$UBROF7hct61kX0G>xO^a~AA*gXhTjtoW znsuFePxxn73oF#>WO-OBe2cjo92!(<(Z`a<)LkJGt25wmsyv8 zy`##YF=lK|pX^tl;mPiA-#lJwX$Z8ea!UX>|4hRbA=+Ov;f8;_`!YAVZ_W&8YCA9+ z2qS7(E}jv*J`(+C(>!V>&S;K?qr(#Ll84Mye`kPGzk0=C!Li0tkV&}E&dmDjb@UPl z8BH0*0to|cvf(l0KUUie%~+-T5O3*PS}qMJUWSf zZQ%6cZRDN5!S~M=-cM5nHJR`*e|o8;5jw$#^Ah{%pXK4SzQ`G(cCkVM&hYIJ?l|ce z7W>Esrk^b|LQOLWTNLQ3YCwZ{FG9)iurL%Xi15&EHb}P!TcpX=Ld5QYM2K#fd;S3n`3JYvQ81F0~rThH+}bVkfV(q;ej5gA5Yl zNg@eo-gE$e>TUZNUA8n0aBC5OiQDBdj2S~yXvqA@=N|uZL87!cVaHiL?kJ7jc;a28 z4Glfzi1}}Tpv(Z{!TWR%6{?3PFiD|IpQZLm+;*pc}}+x}I&xZFy|FHEAxyJz-mm zM4+^!(qznR?d`swv0s2QAEch~M?AVeP@J@z=YiY(G+*H(UPMr_N;gD>TcKeo1P^?V106D3ySNQ6HOb`7d%#qe{D9l2vb?ZVL^S{uYXP%=%STlFyubT@hm! zV4b`Qy1$eNC+F7eH@WCVj(devGVxXV*y0Gnr-7{xDS}9O&CW@#YdHkGeVNYCTXm!7e%4#rgNy+oIUA2~PH_hM< zt$owC^;??*-IvhW=5Ldw?D)s@?GdC{4JPFsj^J?9HXu6vgT(yzR@Uf%TU1PO{`-ct zLaYB-eI%Vi_f+!o?T%Jno8Fdp=P$kFZM$@EI_PKacSlg9Y8J zmPlj^kMWK4=o1?BN<{=zKsRm5`fz$_{v!+!E9~>bb6@K;(fN;#eR)E3-^y6#+`Y#py`y}03gLw+EdjD8g#-6b!%4id@|(oUmEv_>f@Js0q+x=BKO!Uy)$xoWKO;2n+Sf-J|I*Yo*7Y?$rE5dq>PZ-_4BMHAPdt#hCGee7T*cO2IF&Y0cC?*zt3GAJ+?rEpgeZLrGW zOrBG^$5hoky55i+1y`@oDiha!J57lTebc?cVcy-D$!}M^)cUC~Q#>HmsNT1(j&`~$ zK=8`8y=8WFuKW&1$>%?Mo~O$62W0pDX5H=O5bhS`61p1Jcys8d{$M3%Nk8eu$>p2B z({)lZJ%@#rE(Q_i?T;@yuuU3)< zp;mM~JL6du#c`4@VZaz1wa+t|&)XG!ZigIRB{(*H9e+S+J%peBRJl`z(Zw0N| zM$%*fm1tF|ol2eyV6g`laym)k`SzFy$Nhesg9a9U5ch5AT@Hckjz8HqdmR9PivB+{ zp4SV|1TYGkhIfe{JCDI**>o%6Qr<2-aPLk0aB85*+oVFfVck8c(HxkY9HtAIMMVvc z@;U)l1~@D=w!{PgP(m`xC4ekCbHaHn`_UrAHeO=^n22ACcJONAvhC$qB2h5vU^WMk zwzKVApC<-LfCa|r^pHjfQuRyyZ&rt|PGLQw6X*ZpfLE}O#C+B8{chshVT;b?h-J*V zpK~D<<~Mmw$#+=jLlP@)1i|YRmPD!lJ704OWr{~5z0ZAquivx*!y&!*Kh)e4jb-#T zBYgSorX&cM#;(S=d(!Dh&v<55fqE%mQ?KwB4}CM7aGrpTMk8A$|BKv8{a0bz6T)c2 zN%2yw&C^HUnc`IU>j>IOc9sq~z%N?R?sHh&?6S(HcGew{NHvd5ukl*8j2p)qEHhGh z=VJ@TVx=JzJN=C913(RP-KNG@$1RSW-9mK%5H10S+4pn#(n0)=5~l5*!;-dvEiPBT zmYSWje)j+~1GbT-xce5?)wBYgAtd}~z^!9V8PKSvJ2pB(%obG_sYisK#7s(J+4N7| zZaSXkOMfM!{7#Q({5Z4p!m8OH=qk2!DxK4~a#HYK_bF~26C5uaroQ$UgUY^&p90d8Fe?kETeUW?dzk~9j2-?t6!8XDz zTkr10@0yK{MHvb&MmD&NHNj(b9)}l!Dwk)ieMUF+Yh4$702(}tGgQY0C~_vWgX8k- z@4rw9osw;$xk6qto ztTW_+fM(9vRSlnK__XV4e@4H_zrIM3ko52E-?aj=<8tK1o!h#~B;9c9x`7mgzz7i?Nn_EdOq_INRju*Ro05Nz@Nt%W}G7>ZNPdzymm zklandF+hJ4cB%ntafWbBm2!k=)DqJ2y=#I*`GEhlG>CYf=KsZvSqW|12;d0!XEZIr5z&V`=6*#RtqQk?4t%dl&%RTCY$( zP7hGthk}Y=h=NF3y+T0hpUNlZSO0;SX@Zj!1e^%IsDRog_KUp0`V{}0t{YMey@gkP z=Z=#Q=hc9-XlZnSchOXJQnDM2JCw3WvABy$DOXAnef7T5`NxAJepY<`yqx^{?zUk98X3V8s)C1^w6_vO{ zV+!4nxbDHMErc!$*u>;O8+}#z;26#w|JrZZ_XJRH>k6*8g@4C|ltc4F`@3Y1jvVGI zi)<${t8gf|oF>lxWu6hjcDg@~IpDEUf0ukmEC@bhR2x+N-&I++u0-#PQy_e+;%qSc z2g%*pZ>o_&zwo0pLw*w;KQ7f^PJyS1Lzvw+CnYE5c7O3>A&#lBxJ<3YRumM7V|mD7V+H67Xg@~lvm2+ z=-RO7d>=f2;06QxhN>*oXieOA!21W2C*KyglU}R7;U7%nFm+Jt8+^Dv7LDI5QULmQu6(oJt`JA73oI?tN5>(> z^2J6Xl>|PRzO(HKR(p<5ecH%=D%-}KzMx=K8zWU96G55`>%%(7?ne~BSdFipL`>Us zfONVb`Li@y@aN7{L&EA&z%kQCk(cWi2AD6Tv9rYvYjWfB73;XZ0$_M&o`}by`$dy> zl?jFy)cHAhpIb0j3;GxcO4A<`ANavKnskmG2%m1ofi}wVGnBQ>XjG1!(yDmHW z5#|$OLzkGzJrbr9fW6a90d4{5YMUOc`A>x2oIU}!?_qXRJ5WG51|vHLjMi1w8HUcn zXmzOQytb1Rti(R_w-MW)-Oy1nfI*DZGJq?QZhIThhUp@ zx=EYPhZ|@+j;SWRpv)p#;W81b0WfNZ)DO5m>y9$N1PiJ^ZG&vQfCVZSLDF|hXGHID zpli3cTvoNWut>r(#vVF7!v-7RhsBsrjeZAgEr8i;jWT|}6JtzZro{Yzl-K7-q}QVT z7N0WT^r^NoN)o#<644!FwH&^yFrH<khR8*v=?nyJlm zm`fQ>yYfd)@L&CQ=wW1UYnuYf+Xlq!z@k-XsIdu75L(z>kjY`&a6(;rxa%IeGn`37 zG4ExUUV4!R>iwmTd0?}QmtS+F!(zK>ejnojp%-eA=pDbkGEclVvpO5cViH%5>lpi~ zk36@uH3p;owt4G(tQp;1d8VLUswEQn*(+wX$3l5Lnh&Xsesw+}{GaK&tA~6Q>4{KC zhJWY*CNQm4^S!F`osPFstnsx8*E5%O?Mwah$O8T=q`FN;UhMZ8V_58AXbWYgh2^YC zYuUWoDV)3F7Q)C}bWLdnjqBC|k8}DuDWWhvYvyjUrhS#YFLDDdg4F@Bmp;#w9`*09 zwX)t;w{UfN!)>)G>RxPoVlL|{oX%Ase()Q%*0Y?ICi+$^@`Xv1YKH0KMbl8em4Vw3 zajoFN_Io(?W1r-bM7?K`Btq<8F8NQ-7OK)3oab+!Z5}V<8xJ&ts3BLr67Fa}n?hLs z9Df^qrktJ*08^5d8mDXsbd*Vn<+&C42HWxRO5gNWN$;cdf0`^R-bVq)A2(_KU8IfA zuMsG8YyU^YBen5t!S6KtetpIonVH^kcwz31prHA)4I{4;aAnjEZV2h+CFbmE zy+UW7uiQCu;@Nk>KM7y7}Sy`u%a&3pxm*1x-dlVB>yTv$i&?8iqOCRq;Sda16rA3n2r zja4}eKX^Q1>`zxE-G74LlxNX?TWnlR3WlFE{c{M=Waz05sX~8c1t&+%KfU@WIeP6M zpjQ_VRU?Sf2}QgJh0RxK-`*txwY3zJHgF2^vHkywKBPK{(&6YLX{c$h9Mwyky*lmo z2RJGF1Rj82PK8Lnr%VgO4kRQ8BCS4SA{)V%40KJtdk=dG3YbeBm#i=bCI7hJN~<}iKG6Rvbh z>CA^Hj$zdacgT&sM~6OEt&_*BXRc;$Y3;jWsrNl;K|^sQI~pCX)0dtO^{(7|`pV71 z<*&6BgF}9A+?n0f>KHS>$H9STFP%%7@Vj=p#9(5}Sd>ku!+Q8t1?*?vNLN#EQuK*j z4JgFLrEc-iFrDVTbd%3|_tno2E486@%?8>nj)7bWdzZvV_Z@g#2)FYOZzLz(PNFTt z8RHGSutH!?Rz<8r?w6`4O!3KBx9lE?e}Z_b`he{pyQ&UHrItpKDXq$XhEg1^xrgLf zK22yB1ePk5&O`|A1eOpXZa<4;{%urISw z(y-@0!X_yl;@chOuGoNh_p?8`SAS;19WI^Xh!K+{X<;#an>3K%Ql*{vezUkx9;5pi zGUf3qLB~b;@xYL;MyF>^S57y%w&K4J6R=_bFHzxVO7CKWo$8;cv~Rf?chev?)?d++ z{H$WHivL~UNY4uhNb@LX{l?K=el|P-EXS(xj%N)27ld7p>jj_zc+PbImyTTbyC_G6 zXc(L`2YtaI?@<7~}xGo=L2xEWB#Q-sG<^%f)%LJsqdVnE}>rcoQ; z-gTbCW?if@?{}0f>N9bwRBR`oR-^G-#OG*I63^pS!Cx&$tn4kKUeS5EUCw4QK{jPh z1(%e=>5kBLw=$RYe%W<-F4t6auFg87oM9-cBJq`Sg-P4RU=&99t7cbdu__TvZ($^e zl+{Ruj6;Vh)qJ<>pG(_$CNTKV9rF)cU70K$E+69|gTI58BQ?vj^Hn`8E21jD$l1-b z$T&<4iqvxCI}MgiMSbiYNtS1UE1Pv|j93KzK1=)hXszf;;wcRTj0q9b2iK1=k6QcJ zqB^Nr)pO#6N6?bf6@o)M4B_(!%L}}^JON{Gh~s+pw`GrqokQ-qId=V7RKmHd`s6Q- z7Vte&(GcxL&lO*STDAlZL%#15j=0^TjS={r#=c*Ru88rAnh+Pe6XmP-hQ-QxYi{vU z?y$SdE^G2iZ40h*ZusNH*7)w#(Xrp-u;;!?t-+*T4=SLvvQBMlExCuA+4Rc=xh&6* zJ48+hA`Z^;-4cG5gR5G~vL0v8>V}VNL|kF34aVE!X_L1K?VH9H7&NvdH%Dt_1P3-4 zy(l=tVG%eZR3?E>kHQh|R4D7aRy_Oe+G6-H)k-wadFv1czLY+%hNT+gK08#Qs*vgRnmRS$IGC{ zanzM)%dZlSSC=Md(BW0VMR(&6f)##V^_i=IUB8U#FbKD)lAodpj@|T_cK%HBZ%~r^ z40%&V>*sdT!Q9=`oX1ZCga@a8!;8g+eTu(ug=;ipGPpZ)WNlpsb-DfR4DJcmDz#qG z>;8Fo^J>90LEJP{Lj6l0|4<9{wph2Mfj5fH7jD~glkJBeu=6DW^DNkQ*A1kedB96D zU2KcPn$d7qM%)Hc4OPhmdd?6Q20a4z0 z@#ZQ$yUk-HQ;rgkggGQ2V@oe2F_PYC%#+BEKCN_9W z3=duz@nUi~+G@fz(VHPp5-tbrE;gnnXUc(zPa0#S-xZn@YmRK%vj@Bz%#3#W?=H&I zxn}qQ^R}eT!5Op~KFskcf<(@X8tIt!L6jaD#n~8BJNW&I%kpLj+~yn?#2Hw4$~BNk zu+*-mSn9*PaBq`;{Lb%d>xk4re`u<(nwrZ9%jOiuJ8Gt`3A*>FOOF#0Nm3x0LAt{` z%tZnp<-%3`Nu=X(Rcb*Nybbp13&)K5Z5==|saLzXA!G|4iHJe<$ zOlG7GzMV+6wl5)LH`{HJ|zcxbmeu}|qS7B;uBU-7vr&MU&#gExJ5&d7&(K+O9?a}}FUZf9`_ z2HZ|(Z!Bp$^}iH>8{c~Yz;}anr?pTO?6|CbbDfnmYpgxIoTH*}RWUG9Dhey#*^Ui| zb(u(T-5-=yfzrLgD5_E5X3l=$D!Y%NK1S(1=wRyx-IU=ao%>S?9_u-}aQr%^{&BkT^<8k;8DnY|8 z0l!Ye{$89?AF~t5cXJhp^vv5~d+YkuV1lU4Pb6#SeB3cjAfR;GbOv=;R?ICvUFjpV z8NU+Df}%UXR41!>`xbGaqn=x>kSl{EW~;Ubk6S&TuY^>m^_uRYaMg4XS@zZnN;}Ud zPD3Gee43TX{qYx&3g~-rNMRZU^FtTd_`K|3_C&Gpv`OLgl<`WJZhW*FNzS@Qy~gF> z!OQX3Z2W1)w7qQJS=0!KjAk^a{sn0` z2Vc5GJI`#@x{G3c1(s59&`m{18FG%9!#@Mf{G~B3G?Zs}ZZU>sw<7daWwm|&sv)LC zTqpG@f4wP1D9^W*k&Lh=*TI5?)M+3zYR5*B&ko@(fP`?aP~V&#&wEQaE>Fz#CA8+j zy9wflm-xJDOt@vjhC7ZIbC2oZDo|fvUb`e@z1(R~aI=l;*h+3U5H=*sGx^te+mD4;?Ke)vjuWx+QZ*zPLFY zOg~BT#3OXl^b*x7g|I%1@pjl#X+3%59=uVfI`!gNLCcF*B{Lo^y4k#XmK|?jCen(A@pCs8&NTq1`3_OxfgGjK(R0;nPA( zVoh<+O~N64B}Io1?{-I5P{ir_8>jan6|~NA9>@3NW;QZB&WBQCgb!Co52Z;VZ!W|k z*VvDXJuk8EPSCV_@S1a2CV8gX-Ab>}MD1o-M`CGwf1F+ZbrJ>p6E#`WR1o&D;{BII!p(+|{oTA^9d6G^MSZSGx<%keKs)Bh?lZnfvUfMDMdyTU-=8 z|EX)P-zM+S5CXAX4Jjm>+H3usf94TVg*oRZ&i;3EkuGy0uR3R`{7zW{cN8sn)gQlV zt5_*TNqnic&g*DJ8gtuQ-0?YsQpOS?L;we_N)2I;`885WTM}3w_?>F1rR3Asu>9g~ zbrzcGP^?$>Cg=SgIV#Ma5Et$PX*9u7^a}~TA1ejn_vO&bz2i2zAp7Jq0f+hdqu9(? zjWuzhaBaLtRF zKaAR>8+#;t<+QZw@HEn}?u0F}GxZ6hFF#DQV$Iq%&3c$Axp$9at-|hDJ?H_|ktmGJ z049|Ymtm8WyI;)%f?ufXm0n3!@>}u_8~}Oo45&?7WT3z|-wJ#u05kBtsn1i5LHqm8 zbWV}XDOQfjhqCJ&aLh!Wp!1vkP+|_*VU_Za4GT0QiFpYMZg9ytDdU9XN;Oox7?uEIKYnVYeT4rUg+I?2nSjHQ0J@+EZ>FH%tO-F3?F`OicANX*Vnvp! zgaY$B8BlFsu9}I#i{2n5;m^-b)!#bWr-vCAj$~yla+wFV{}Btod+)nD5I2rTstEgL ziJF2pDs8A;_lKr^MW`fiSFCW4IAp?^$L0$^N35lEzACPITiDH0-LQIT*wO|%NEq)! z-B_k;cRlGRjcnNh0!LI0i{R6fL%NYAnOVM51%L9VH-}}$*2Dv>QaIg%OfW%#$vuRSARW_b*iCkNy)$UA?!ZMH zY1oDH)xs`)_{7uH9WlB55xFW4yBeC<_A+wIs=quH2>tzC6m11-XsYJx_)T>YaTa`N zEimp>q>PE9Cd5N{sc})pc)Szp*?7CV3W6!Z{cZr>!p66k0rQ*^)EIEm1*QK?MuBDf z?I$YTB%-K9o7{mmN+$>Rip=wxu}6ld zx8_~hAKPa3%IkcSVT)K2<|p3NqE2EukM%?24im_a4;mEdv!!?Wbrxq=<%s8U1;!?B zxGCS06+g}81)5Sc;IAH>>2sL_hHby@7TuFh;{tH_XY7Lw7HSPa?q5}p`JGZ-Brx0q zr-rLunMOjHAiGyp*oKf4$JbkL7kmikKlRdN3kD)`K+Ee(BGaYOKdX@q3!#cdVqVfO ztmn5f=gckj)9fG^ftW_az4z1yW4C4q*o8W{my5&@OxLNdY@M7}Y8-_|)pMKX%wiMu z1>YyyI~ng_fLAH+tPeDh%jV7vR`Ydm(thB(Ac5>$hwmHM8#O9 zOSEs6d*CB8h7kop3pli?c;`OgTPHyul9Yk3kk3iw{Z0kVp=V7TfiXf&VD{%M`8-2UrMfQnLbd+58?;6SaO=E4Sf;v3llerkM0JOU2&vI zE*>^t{T9ykjWMsfVO`XFuNQfyI3g<$!gtV(nP9QZMy%F+w%CKF9Fu6Ef)W^f)gs#vHkJ>_fPn^t8HdeNt=LQWHmb|ebKWSPg~ zA!aSM(XzbAjz~PBQPabFV1jq2FC1q5-{S{*ebJ16sd5}i#|!Ci+g7F+ZkKHFoi2++ zMk4a0z1&+I83TJ%l!(|zc({AeMv-dn_y9aW?)Kcgf9~mL3>>QLRthk21N(pq8jw!I z1KVHR_){xm=M7O)&rmz^6QTPiLsz_MLq4zJd{@wUGE4Gtt~mUy_OWJVAAU~TPcXv% z$$jim{G5_>#n;wVEm(GL2GV~~hif2S18Y;9Ay4%XUR{vMoH~`+y+8I@`Iy|Ku@Dsz z0rKzt;z6EB7Me%n>A$Aeok+zWT%IQE3T{kOLj@a*JTPb#SlP@KSvwA(Dxvcx#Ri1Y z6L#_LJCAvar>|9{G`jF-znZvRI9aGu9rq2X9x|^!8$M)==^qA@=LtipIxpth1=>5pKO~noid<}Zc?ZTu~MkS`;P`^AltF)n!USX`0!$h}@lF7&WG;!^`*q(E5 z?6W1Mp@&CzAGKIhZAcjC^(*apzXJ7}w^2^X-(A%*h_uXj6EM$4gb#^}t$9h{W84w~ zbt)ktv4*k8n4^q)TS$&9q`X+YtiFQTmKI*fs4DqReH>c54_h&)cVuT$uY0a?(?SeF z;_HWK37+~$w|^z~P&UryyQq>tnAuZ}aNrubs2~IIRs^edV9gOukbx4B^oWG*?x+^U zVN;tbRbnM=H0d7TSLcF<5J>kQf?n8Hl0raa+ zy~(=sGy$2eWBu>6t_S=-yJAp|fCaZ}&Fe^`CrFtw zltqjup2&93W8XCqD_7k1gUrD`pDfx~0KJJ^*JU&o#xF0YWrm%H_LX}*(A|4y**o$! zQ_=WcVed<~!{yJe>9cc0<}*9$RAaQ1r-DX=zJo_59q4qo(x#|hnt1uiH>4*|OtWHN zZn%lPs^xHZj6jb758`-Gnz%M{#h)u?8B=EWQnHYCz3~rnj|w!DdHR1Cjc+efWn>z@TplQwScEqRJYni|dHCF?YEJBUJ zY_VA2wzdeM9wHfN9x>7{yZk+`sL_ zjU#`&u#<~$HEG#3ukZG|eH}T|?9DD&8QpfYfY~^JlNz+nvGjw+%UDFWeD?JRneKlT zQ)gxjEee7XFtXTe)!Ea!X+}Qhhs88VUkfrSlN?Y*U&T0~I!8t$TAK~XM?Z?A!k;-C zy?qOl;GoE#L?U)sYbtq_{x(b8gy(_s9h!8=GZ1Y8b7l+Q82$$3B(@|=x2AcY;PRa* zZc!BjB$4x6F7S%GfUYmYwlU;`3;~F#F;p%rD6jvc!l(e;c@rECo2)&zunMA^Dw#F7 z5%3E6Yh)NJePS(7AP|1Yxa@GI5WV~F_Ty@06pb(Wg>zh`d$NX@!sVisa{2EQ0m<=_ z#PJ+4FLcy!L6jh=MbYot zG?N?~{M~4A0)J21f0i?70uv9=NUR}&ZNsl+$HGASdTFZ%6edIB4)P(06a5vfBeAxfJ0 z>}9&)YgAbbJgOa=c4~;MS%eIASiKCWId`eE(nD1mOzw=h^Kb{tQIWp))@p_Ad6Y2=Aw&ONGYoa+1L3Gr}DE z5BFn}<6P&|^K}%`;{Da&NYP{iz5y@T$?Ar{#f9L+8(?qvWOclH z!hQXA+M0d^P+tzUlXge%*|)IYTKTyPeMyRB(A@RkJuZ7KxA#I}b&;!ddA%bvV=8`9 z&mSXT0d4_3Htslxo^-l`cN(+mki@n6}4sQfXT3vb`b!o}pc z2rEL#o>z96)8lwos~6B}RTDnwV=B1P7+f?)6e2krltX;b!3>oM6g>9Ita;jH9r^J6 z6<#ulA>B;(fQ9X>D1BclZ`0x6tgdGeF~9q9y$s>|FK=d#vC5b+se8n`H9({Rw{F*U zXy|ChWrWIslt?VZF3U?*kMXUm%_LCYRbb7prT$K|c`~~e2J==2i3*%A+uMripuZmk zxxO_IF${0#HJGmkr|}32*d@4u`lXitx>vO}o3>wnYa+#13L7_;unBvDHKDA6R3T(fg}vw7V-{oXge%gy$|C$w|e(myOVwB)WR_N_my|P$yUH zE{0l2$j(^$C7~dTxx>&({Q!cDhkZ9s4V?sSG+)(6WteY|AzYWY%W5~Z(X!#OR zZ*IFQC5_cE*o|hpZrQ!SmBOa~sVnUf9Vg>45FoXV*9O)U?k#1eS@{-_#+Zc0_4~O+ znr<8=YB!J)kg4s_`kAV-dMlTsY;q^mS}qd22R;*&96^c=Grsj!ird!o zHwvTOfmM64ZjR?Qk9Qy*7m5%b3pq)8B+? z2Q~Yv`WN9dlChf200GB8&uYkke)kSoU+)H4og0sF0gEN^?MA|S1g7T$PhYNP1j}(} z@u*HV-%TXTro-=@!5r^+;WYNoUwy>)$ufYhY4k)FbUuXg^=n~k9KDzg*Sv;7E7BV7 z=5TNhIe9l-I9di*`dWxlEsGBXX43Yb7aOo^f5>S5g&NAIM9Sb!pj>HzvGEV**BAaU zezUim_cn7T1hH91$`H)hhJS5LdeC$Xswk)Ujdy#KKGhCocK@Vb3BNnxsD<%_EukqG{ znm)eoo^WjFrG$6~HB&nB$C|ulVR#|L=}E2!mj#g!7ccqlXg+I@bHQ0=-YZ-+YgLl8 zOg!MGMRaH>#2SpnEpbY8(4k))h)yDzO9CD!l=yKkSQ%%L&yAsC?Z?9MI9>d?a;CWK z<(yM^8qhRM$@i~QG`_TiD<6=($Fx0`J(vptJDo8v+*W<|XU^suqE%;kpd3U$B&9T1 zDw1`aJK5*LA#cwZFaxCMt;EsM9{J}q9&pglA~5G(oay6uN}tcWa+GnIfYTaZc)O>vL#U;NLyoX5Egj8~7Nm1UV1AunQgm zdkZ4!cN|Z|{8rSc1vQB`G6n`S8_p76jj7i4FJ+juxpN{qMIOBh!6P1hON+Ob&VB|; z@phiK>(cDq0N7>t;368*23~2Le5#N9oh;lS+zI4CuL>W*JGuODCruaHz1$YK{g2Y^ zJ|l~~rx%2p(5EuIf3zEQbC!>59on6*auUjiBvB+xAPalDB-jBV1-A6@J%OpOE>xfC z?*g?ErwR{z37=BhZHJQs8X##SL_QB0rQ^O@V_1yfi-}xv) z7>KVUrSKwmPItNE0FQlSl*FLjLJFEIpKzrFHFFrOmA2hc<6q_7Y19dI>ju3I5Po?U zdH+HQsx?e?RJ)y)H=amqP)HhP_)X(nwxGvlTo9+h>Mi0iNjP$w>&OI1qf+U`di)g7 zL*yJ75+Dob`g(pc5`o>Y@H&?6SY(g2y7s#tEy$SVl2^(ZV2f>gi9l%2w+xI4-!zWJ znz!uVe8|__TVCA^kW6;fEd5Aq(-ia@x1|+unz)iC@{}DU0}Q@M&W0F)0O1{5T3DHf zrN!6xE|MS99KUbq_K(h2aR^cJFA#PHem8!O(^K%z!TgwPW`yiTjkk033o}F*{ZKxR zMu1}tlT9fIY)-?J=w-SagyEm98)s5)eCLiUsLlTK7hc*$L3aS9Qa8;H^gCJ^M+2}ha$t)4x)8{Wn!%~)U=fvSUykpNm(v?H_teW+W#5Ve+ zXIbAa^MIQgoBD)&vK|mh4PT02D2mP0{dhiwc1U&m^_!LCN^_I(-Cy=&t?Kp1@jKl6 z|8pQo?BRSX-aor0>{d(Hu#35z2zQ&gQR_9XU%HOG`kNfl*Eq1LggG&G1KNiK)8L6A zjksM@!>Rfj0ViSDqAR2znpIM>xDPBAoKmq;G!FB*t}iFm&n{@zJvw`>gZKleNp$nf za$(#Uw%@nO6qQ+ENrBaR)ibxU-FqUN5;{*X0_Kgi(lUf&pLOok8hNGLq z`TH1@V(3%?D~Jo+|K)wjcVnrJ?~*MSMjZzScq3cLZ~pv$e7$8@TkX2FUEHNefuhA- zi+iD1p|}-ycXx;46nA%bcP&yV6u00Gf#3=9rhDzZp0z)D|B{en&Y9dcu5q2i4-xZH zl9Qb4a3i>A7j2?f?6WyUKtX(U$e`PERzN;SAf<&((Ef4k7sku%?CXFu+CmvqS_Kv$ ztKhe18scqon<#ti@g761Hmc>)6;TSSpLd5^b&V^}s^UXu>xLrr{lISqnUMMsPCWb4 zcQi5R$bY$xPN1|hsAfzxpxc&qi>}1mQD{LIK{-7@{GIBvv*H-u1(vzUGfMKKzSrDL zmn$tagV2N2;4rkJ?%Lghf$GfM;{327o~V`5enxM4r7exkiw%zQ&{vp=pPWrc^eLo6 zzvbk<$}3t#`C9Zv#!twiln9;Tbo;B1N9w8VoY*ebEkE_rBM$I=D&pfymjiyaw(r%W z+%;KhM@zNYSHdsihK4xiClZwa%|A?5LCMPcFoS%^rPYZJ*3|!!JpJx>KZO9lUXPJ; zKOzBfQovX(c~-b@ZKLD2@b z;gdhR-%Xu1To=*q9nQ3i4O00Ut^9L{5S#Yahdve9(^s0o5;^@ukb7!t9);whVBlXO za&Q+XlPCGh8e+6N1N73HL021OLED(H<82fBv&(dbQZr2O*38xPv~*x!LH0}j?S}_x|IvKY z8ycfjkqMr&-G~yR^LJ^~{%v;UcKCJePtD^`w+NmiZ~F(9XNRUJ5Yg>{P$9k=8@f)a zY@$SH{jf%A14m|wLO=hS;z^bW-!dTj*?ZfU{OpVA>h7>eb(Ts2uz1kqpGEUKdr%b3 zT*c?AI&Kw8k{-a3<9RVPrw?}*nHTDH2Fiycyimivr~HBTEXTCdtek zkrorQ-?h?C+Wd==2eVbw$BuT`Zd%rv0E5^S*{B($FTBgg$`uplwmY5vX0deF_ZO-F z-VkOJ`tK{e+I&?48=jr}5RL9z;C12gZ(@P+y38iSu;4_A;>-)nVfmb5dL{H7enZ5| zU2iEzT}rARqte+L7uapT{oRk=R#6pnK}&U3zy`1yKD1wK8JU!sog`6-$$!k2AZ2r1b^=}3Y@dB3*O z+)*_|NrelTY* z|AWJVLCR!oHCY z_T<;W@00mkx?qtD{MJGvx(7R|SGkimQRl8V)!Fgc;Tt%OMnDMiYCfJ*4h!$K%r;ar z4+w*E6+!ieyS)Pk$@uP&;-8mT)_%SZj%tZX=&MGtnS1^^XZSi{=;q zXt}BMcv4HUUitv^zg}hf(Vqhv$^hXQ8!n*G$!5LKma0t~=`MPRm4{ylNuAoA8 zg@#>_LID*S=@7q9aS=PB-o4G>z8v{Jtxzb zII0#Fjqc(|R5`fr(-(L+4T>YB(QhI4jg|wtyD`(%F&Ug4UJdKc!_^k?)7?-r|F?_f z4(I(w^ZSl89TnmJv+VG1R;+N{J3Ayxe&N?7>?ZGnZ>-x@*?9bw zrVSMw0(LZ{92gD0H_E~us1&+;&taaIGq6)t zjaKqR&{RVBvr#hb*F$)LZGY#1yLQzixr`f>!NH$pb<0~d)gkt>{EM-x$HK;Mm}cK0 zA5bVZw{tL7TOFP_t*}`8va0fZyzAnCO{q-@q?GT3w1XultGw>}u<5!)q4nN!We4FP zd%ix;hEDP)0Hu`3=TbxM=z z5#$vPI}p4)(C@#W1ORx9^ zr-G+Q_(JB~gs5Ee))Yl%W)sf0)#H;_-X}Y0cyEV+y@6q{NcF6neOoWr%@5-(0(@|g zh#mMJh)xhTN^#$ZFz=fS<`3bR!i2SvHgq%{eFq__jrd$uIYp`-z|{(Gq5I}4kWeyY z{btv@N)@ZL`3Ys}_S5f*xC~nC&>#j@WOFp5Sb?_?bV?@(o2^bWC>{9Oq!8++Iw8;c zgn}`b@-4&dXbZ-risf4ym(Ig^ouJ{l?{5akX!={JD+EQm8-e?6WGNlR#hkD^8;ago zFp&g1v6y^g>r(06hxCzPqBcS;ieT3PKWN!`2XFD6P3ot5*7EcOG^WAy{=%)$PagA^ z9~$2K9g+AI=vbVp9FdeOjhh&I@7aXlPkoFwM1&-0>bK&3_}kVg_sNOPJkRN3zC!h6 zAt-mW`vF?+Tp{GP_A*!ekRxihx`j`(sP5~x2c@Nm;`L(J6G9DMOK&28%{%sU4@*5e z-{%MXyfL(n`OeoMk6KaQQ*k4=AJ}_X7b)r&^K(R}cYC~EbF7xtXKs(oprj+bxkVVs z&FrV}1)@-o%U|QW7-;-?$*o&q)3O;A5zR$KKxl75`dUAFmLqlc;hXDz^(uAVv@~%_ z(AR;6Mlvz@ff#G#UM%;fIH1`h%M^?H6@IwtWI_|861lX-HE$L6Zlq(=rzor zzC4j`c^3-h3Rq<`07gU+gJdnb+Q)gIcGXZc_h?M_jz#)sJ4eiiU`pGE-egKSLcb6_6@*74l!cGhP$7S|<_o793lW@Layi zV;;E7vea(!{P9m1(dyVl)Y#*|F5NLetE%RV_bPqUW$$Vl+CWoap~0%&zdTJbckYy_ zBsR+rDA$CS!o&T{U4|;5TDK@I%*|s2R z|NNJS$sYp(i6(Bq@}8+m^Tqiwj==Zgwx;34v*x(UsQ-5456q_34a~OR=++;^Sh9Pc z5<@_l(%M^pTq8jud9s*zU%}hqvnO5Ml;9gJ1X_%0D|vilFar zEx%FO1ZQoGaVKTw!z`Tc!<>{5{6S`azj9=yhafY_`~_aoaqb|4dgFR}Mz}Ie$!^j@gmjnRK!5AEFQfPZd=#&#Kef zEtf+Z3*JApIY@x?aLzA0>9fm!J(b$;`UChV%0AYJ(H=fEXua4Ni%%*~#HK9-a7D!; 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 Mq#^_3;m%es!)o5^)JlBXR3g%G9I~p5oIi>_ z$KT&*S8onw*FMB#<3_7_iV_T!OmX03vEMjb|E5YVZVz;HzILJ>y-&S1BQNU4jk_WU zmF2(i`E)oJ;tQI{9wD(!dTi#F*4(6?%J@l0#*e2OZ?VPUI$x|lJYdVu1{~MH7b}oU z7L(Er5`=v6XHzT`E*zHt50Vt4mLFdlwvdl0?Z~0;8yOO|RVoF>taXZCl#dUWY%8|E zKTBQ0#(3@p`-Xagdi<^<$QakM+%IIC8rKyNlL6aIVE-Op&jQQtw-E(A!Oz-s^cy1o z;JbSYnZ%CmB~bG7Pb4GE(1@ykC&Hw(F2VsjH(y4~1sS*F9l9#=8{)!cMO zVETUsbsJ-cUMt+%>$A+4C+oYCUXRso;4`;5wn=(L$61?D;sanK!#|)^f`D2N;xS*& zxm1}o5i22V+6N^%zEL&kHenX{aTmKlkb`Z%#WZP_{u5v5zjAB&@smc&aVk&iy-48W zVX)RI?+8EEA<)76sl~F;$@za=kXuhXyIH+UqxO0y6FH_MLBC^fSEvhI9FhxU9HZ66 zet7!e@5B8liHf~|O$}h&awsZ} z4Sb)l+ib4zIncx%De}r^^LnWpq`zzI{0D+`!(e(dDDt6HMr3SW4kj5fyX4onSd|m; zOg8hrEXHU`+?iNs#RwLt$Z7j})YmEGQ#vG#uS zD2pD1QBNy)fHro!k&QUh!(rZhDng@Q>JvRmw`cl;7!gUBDS{s@?eU^hd)Qsx&MPex zlGH2y7vG<4@{mN=CSHz&dq@+FIWZe?nB6nhB~3XhgRV-D3|$y8Iq$iNwYABwpA#DnB1QA}`fs^eWK5b+9IW+BaBP z(du2`vjys7L(lDALf)=*t|dzHJ@Qje7yd*58f$ziZaZ2k=}?PC@euU#%kxq|)r&}I z;t1pp;gV?X^>b7@O{G7%Px5tUq-I=u?#K^RXVRU|2BLDFpV$*`oBjed{f=wpqwb0=a^LdmVNn{}b~es6ihOo(6vXG(6sba~Ppr-n9@Q(Z#-w@B8l^6oxZL6#1wg& z?3v(EmRUJYez!pXL&~xP!*zlB34Em*W4or138bAp$_U5Ac+~JB3cCtM+rh1UG>$_c zdaH~^Kp^(or8f2wmxf>lHwbyI>I|XOIQyA81<@Y^#O=4a#^h1iaS1$#AZ3gojR|Su zo|nOEZuOtIPLS~cDmqM2ac8ZLfA36PTnLa8Lhs$#@s}HQDJ*VEuuj;8IY9T^Ew+S;{H|QdBX;$9%jak3k!D1(;r}?c=#V@35jT}Z z^)8nWR%a)u`KEyyQ`y<11hkJ@eo854NGQ`6R0FD&MyhmTS{-sQL7b#Mh)@!)7Uu|K zv2~L^sdGHzSgs(~HuqtD>OS)OQ^58-I>3myb*7#l>XqZ!=R3PytT8X`Th~is)JB02_T?Zv)jjP8bUHhO2 zFLO?2<+i>!eXH>BTmCipAMPBuFAA*0-=Y3q%j@TJ>0_yGz2XWI^AobyP#cC=gY6Zg z1-HKUHIEctt-xRkngq@@v@Lt8q@sUzEM z?B>dSi%3%YY2vc?am&BOzG2Y{nM-Vj9w5WJbqcHH%ya35#xD%qEK-b7c=9Dnef6BG*c-v{YP<7W+{ftmBuqP=DDp0)Tw|7HkVJMd=M|X&W+`+aGr4FSeD0jJi$?p_i^Q(YExwAfM}Pf9911;eO#8nXfi9 zZUvBEi5$bQ%!QCOa1$Rx*;I6^l z-7Uf0-3e~NU4uIWcZZ3)+{%)D*1mUt_ngDqd|+06RkLc0(MSJVQ|Yq2zZXaTHw)mE zS5t`hGJ=2DC20QPN8^#yDsgu|beWZUL&&0@SJwJoYm!scMZaIK#rwZISv1FScV4-Epk z@=f25L7ABpq{KYyt%)t7Q9?^zr5^kO?HU84QBhYwjdlmHe}9A}VG30E0UNSuB>)$^?g=W!LtXiT_d)m4zscPxC|pP-7@rJ%D}Q#)!u5AZH59Hp>R zG&L9?m7DgDcgobjurvhIdsxAP2ltNk=imu_H9zgMgWuq(sNK+GIUP6bd-d@+9v@2u zfI!O6Gljv`!D?R3hN^yYGt9+%4)v)5>4xLNzGCZn$jIZSa36Q6AZE4FP1UbeV>uu5 zzA}$5lyCHUF!yWi`R>zGJjRo_pyEF)C}(FOUCsbS?K(xmuD06 z6mA@8C+iW}cv+4Z0XwU)3FAYQOw1(Twv3h;x0T6ns7aQ_=pft;>1=j|XkA+npFrE7 z53~!Brl8YmwpuflxO>J2wa{6ddoG;vK+S45gAnfBhX#h&gBoC{C@D2eQHohJILDhK z0EQ2GAQ|NKCLk*O<}^FhKlqt#k&$9Jk3zP}){Gva&Fu^$at&}B;=;CB&anugR+cHh zR1AgnZLx)-y~}rMKVQUAZ0kA9Go<1B)wrcbixbzD1^wd8uFb!3?%dw%dS9A*g#U!< z6^*7*!>fUiBzSDk#jfR0&D}sV-$o@Cf_(psKKQ{@t@e*U6hOEtV#Kq|+YSolx(In( z*BWa`LV8o&x*(#Sc90WOG9sV<7ByvG8!p)fmn4*km|>Xu(oY6AmUAEhfj#xIKB}cw zG@7`7rzFo(9=L~fhFJXOAR(T`+bE`ogTcUbtKEDXcmrg2>6Vd}i7t?v&gX9`*7Iya zYhl8m(AsH#t5J+4CVaArKCymAR{m~Iz@n)edQuFrD911~w%W@a?~761PGo$-gUfFC z5uMtpVE)d;mx7L-!AbZU|J8JG%&#}Qz$E?3gL+(-ZBoO|W~nA%#$yaNNW7{k_Z8V` zy{00#Z%X@x=#$)a!<2eROrsoa1_BP-R8zOJ~_6W0#zj1ihbOh9e^2g-JFi*yio{L%Vvt^ z+SEhmC+svz3oTNyf6j5wxiyGY2u-2%q#~M~M;06 z5Rhuar0p+{IQr>9+HVuTwMK1qe#sspxkMJ8SBB%mPfQ<%@$huT?tKRudO}g}klYk7 z7*M=N$DN?kQtW}_a>bib0uA*?q!acN!Qc36R}n`z=4g)5Pg1rSNHwx2%X`xf9Gz^? zExgV~7x%l#$r%(r=NX=cIDGPd2-P52iA(rfjk9R>b&wCd z#Cqh%q)oR9N@cxqNV#L1WO$-~^O6a*rOn;>L+B^+G5&1Al||R5;BY87*zCqeW0ga!)JRkAt7rqy!5>SRrmT$OZQ#;g+pJ7>i&n^$U&N^tDQ|1d>W3 z+QE{g2A1;xlVyga%Pbi;7BT(5`w+2B=);ppul80jh{o(I4cl_(b?9#ckfZ!YXS>1a`k96PWhG`onJOrFrAg z_eyL=li#qHpHuk|O!m?MO0qL84fTE6Xg{YfeF`nGhQfTM07Yc67-%2<4XPdV2(|bK zr;(cWSX$s}v54^g9mi#jwxhCn8LaqKjP-i*`j@GilL-3yu>z|;odbzCo}cSyU>~9; zoIc%_B>`3Wj)iPvc!gSf4uky>ycb!$Xf>-+E@-;y4(CYUCqGBp)VI80!uh?d$z1Wu z-nJls+G38yU5X%iX_@sp>kd^zx0@5^r{t^rps>k)K?UP1(+)j3#5j9|71;v=TkhcD=zYS`KV zY@oQVH?#rw-9D5YjNTkrzLM4yq&?nYJpwk#AD3v@I`*6~)c+9`nb3o(Yd-nPM1lJ= zO!v9;LlV1DC*>K;r&--3U)cv?^QN$ZBor9KcKWX@(0*o4w>PAtXtFTpU{XO>3n7WqFKw}^5@+9{x=gS<4p|nJTvOxXBMVOX)*ACBzt!PMw&qU>i{=p`9Nr%~RJy z)vmKnS#m)4^>3cVia|WSg&`~k55=|I{@)7AA7O1>d>D~t_hxPc##V7Iu+Z=8$~^|3 zi94SOFF$>wzEQi!@0@)3{+%E-0NpD*8X*A6-2XlKfv)ID`9bggx>W27b9y$5$f_So z1f0QOpg-!lDQwc6>gHWd&T_FEjsvM*b3O5x-Dk8^+CzG44HoVJcg?ScehzWixPRE! zF!4e}BQ;Gr9SzDaP}(PN=W_+BY#{W@xmCClVbw5%yMK>jlTK_s+_kxexAt=3H6g)f zB0M3oKb1*p06p0OkQFK)wyg-`b%&x{VXmK9I`k92u-+x6`4FS4_1#}gG0 zZRAa7Z+=0075#N2kZr@kcJ9zqD%B>c9dVEy7hgsc;~Urx=G5S$h-Ie>Y&lb`?~x=T z8*b6;tl8}9K7pIMc#j{p-ypKB3_56?Xfjk)FC8p1)$sf_QGDCR`gvm06DM{Dzumf;`LOrXOLl?K6ZtG+3WyT+8K`% z!b|`Hz?xz&B5ZmF{B3_ryeI5*L~whttdq)>Nf|A3I$-J*v(+Im%E5e<_+Mubpg{rb zu?voE17``niX+5q%f?PFP(h>rJWwZB~ch+i{kOS25@OFysj{TXwG)zarYG$Mh}U^KSao(BD(q{yZmhW7SI&n6@F<2utL6h7|}=&i!(0 zz3s~e1;+o5P)wFO8egUxJqsJ);AJwB#lh@bhbCyA?)t;P=soMA!(eye{?`XJh>^O_ z&&cO{6{5}zUL}t+A4oUEg$G^Xc(eq+_@3&hFbFF$OZ1HZ9)DQRG{6?FM>LV-I%H)d2d zK4x%u1G+y&i@aW5FV2_a*m2~P@A^(ncP1!a#b#oUs~Xw(n|a2S1%W@u&czgCFW$NxUsBn?*12v32g*Lbg|Xj-w+BjZy=hD-7Rj1wrmwe9*|b zmq1hlDp&1pArB*xGj;Lz`Hpk!%D0VOsY9TA2OZR2SB;{Zx)8O{mf{eFoiA>xHN@`Z ztGn8@suvx8gI{9;0mq*!XJcy0_as~QOxf~c`*X}C!nJj+UQa_R73ZDrm4Hj^=0|~Z z?D=PpwBjKJv|h$FWjn0p=Njir8pJ$jxsJ5ab_Javvb4jgTv+gvy3X*1#f~gnX*_9} z?KkY(6}m<)A{UYmq7024a@-24!C;6`9R44mOzzs;e*A(5k9xAGJX|Sk3PA%8hOm|Q z{jz(O55GU`$%tANNoZbV+%kQFUdo%_ETJe|FQ6rPpI9$?7kOK%sRsJH&x1%&;5qov##IY z|C?Zdl8ku^wVx0A0_xymI3())x$*LJ?rKGq`l5B;y85q!#J;0_#}o5|Wk<-PLSi&6 zE2D1=d=(UGym2k2)EBv`9pp>Bj+$jQr8b4gIC>9i2P%z0mpXRH>4UQKcV&z4`}#pQ z3u9Nou9v2Ut*^}|EV_M2J4M+?3`jLWmhJ>fSo*rA=8Jhe4E$h{&ee$`qOcE(!IL41 z-Gj|oDshcXJ-h9cMKou()@D6Hy<=K(m}AR>>k;M&c2q=pJ`JIq(UT^{+^IRY-i*+g zxUx1ZpG2mlnU3gbDp33{c@yx)S-94j_u%s^bkm{1ll$cgP|6nB#k`1%9u%gbEp(xR zJWH&C488$dy5>H1h^7ynUk=#WeXy(!xr{?ABbxQ1m^xM;4s-R~C;EC($-G-Z{vqD>v#-`ejPcoV>(RJGhcMb! zcmrSB)>!(^sqd;!s#aYt7z2lQ;sfD9SDb;0o!hHaqfXS4WACRP?$9aN8L9Ru3{a+H zLieXMyo;iXctoC_{jtZlIfaLXPQ75AG zN7WaX(uOX6-2_L}3?wP@;Cg+;YF(08TReF(~U zp{=}QL_<2|JP#3-&PQjzROWe+uuz}*e9xLr@?L_*A5hF2OliQF7uc0<-ZnowX>1+M zI_NjsTxj^>E6#E;eP^JVSJaeHBMBw~n|fe3vHbX)mWDF^TCN28kp67YNmGwDOgyQE z{mESq4l38qA6_p!1g2YBs?Gn=6V52{BE|3oF(jB&Zm40Mf&Xi82x0gv-6VY69m=Gn ztmw=)ohQ{Nx5b|WBv9r4@x+ialcM3^*nR6O+YhoNpTWebFG`6Mdd>e|bHeVlDF2~^ zf!rg<$Gw|}9R zC=3jYU?*?y1&{nBp|fIi`#}Gb?oNTR&?vz(6Kasu=SeL|oea)a%m@AZxfP`AM}yO# z->{+2BBsm9cUhwhq8PFhpDfm(ckq#VE!SZh`a0t9E+j(s9ltJA!1UY*rv8ra?w53D zfibjv2OEMfxMxgF`}_hu)(bI)r0{LrHkBE63(%1!i302ZuMPv+6r)g|!L_SDAV*lt zIu5JFK1#u0j9_T6XlTl@E%qHu*;^RvWWq;CNGy-CjCD~s)b2@i-fr0!59i><+`QMA z7n`dJw96hsUO3aCJYGV(O{l(vPVm`6F&;^MV1z z5UdqER%)7e;`m$;I%)v?ZV?2cT(^o4oJVl23rlB@b#?Z-Vj|?Zv|pAPyhujm>eLF?i$6B*cL*rELaK z)_J!vgMnI1ms<`lOY2UYcRkJaW=zGNPjuBS)?wc_od`<2(1X) z=V0_goA;qH1cQ1(|O)(P1% zw1SNIV+6$%PAe@@D(}huOS(oJZmFB(#XI>X-$4Rq)gUUr6~u2i4$<`wVvz?9kQo@= zUmH8h{OE`|O z(Ns^6ivP1`0EAX7CDL#M&VMYHuJ9mOjSnG*nBzldTus0KgsR^&=v=tqG6ylsd7F+(aorE*Q?0w zl}k6zBA*UA=)1P7Mk~>W@8K#g#^9UTdMELpYLLh*Okcz=b>9{g{^RogzrOl^`Un(c zNsEzuR%uYK{}{{#>^ix=*m;Az+MBfny1=VO%Ym2HH`1E<`s8BD$f9kPP+(?oSp*fZ zh>__`RD@YYfzR}RdAv@EzsEB_;F7UZa2RV>w}|lK^vUK>0oMJkCvL!(k-n4q)02OE zvb?%QacJ1+2pT{4it63b=G1=$l<=Zk59wT5rbeVcm94EZM zVO^&n*e?qGPuK9@1jm0sZT`KA`{$j0gbzq%xxp+WJz2!g=X8iLH+@l1nbOxV&>Hd* zwAv#nL7ZugjnGxnExE#6Xs!4=Pz81a%j-{#e#AtsXC>}mR65aY!nH-(Rx==0Z&3d) zFE(&-|4ajD` z!u@>>DM?Y-5qv31^oPj#hDhS@77WJq`hWHS{nrJG-9WqGzdNLu9QrxstJbGac+Zt| zlSP619H#Ruu5{ZzUKULkXn zS^}i?4&Ph8%9nGTKBXk-pJ9I&W;vA~@}yyL>+#z=_(VdOw&c53YYgji`FMa{X=jwd zPShqz$_8axAt+k#{zvM>EhoQto~>e25<3AUDFuDWi!$od>E~jn@Pp{U+21N8jDMUn zN3dl`V+ejFatA{@6FqdLmH#iDeQkypuLspLP?KBy~_n_ z?WHL^>+nGu(Vo$hTxh@l{SjZ0KmbkX<_^8iyxY8~l@~z2{qMzu}a^PHCc zzUj-%Vu%AR05Lp`r`-|@LC&;OHm?i9n%{;GdG95r?_Vc`1oIU;WpP6T2R@Hc^RP`2 z400(TcJ>fF0AOkbUkfC|z3%{Y@|Q1P5cnnyl!mVs_MWQr3M4fQH{4%c01Ve8wAg!& zX1xNUvL7IF%3tNQoGaAp@Cr);nY(K>vrw%4HCq5-sseNqm7N+Z)LQEmOpO|&-`fMu z*W*o!fb~Ay(!=>%5BgG@8*`(bTkXZo-0Y;{MrW;Ef=AvvtQ3{2{@IiIsS>}J(XYO9 z=L)yX{PdiacIArvBN8N^md>NKl9+;9Ir(c=!*$=~!N`o(1MI>HIl#ecCO=x{>Bg z$!w9mfHP{zc_0P|0F*Yo<#vmNOXAU#m#KHaIf5qx=dy|bQDWRtKuL08sSbL~8;1qU z^P5`Id_FA4^Ey0`faSmk-fhCv5H#@}_z`Gur~Ijw4@<*ZPqoDy)d~Rebt2hElRrbF zqD;)2^%B5@F+H!YpFnTYcDHPG zbg|W^;(st9!_-2lJ~Q_tGYt+2pFj1lHVU9+VW?wfrWH-Kpx^|cTQ?ewrLxX}ihZ3I z*WAJgWS>W&q3qZCDPjcw0!52_Uu`EsKKz*2e|rbu+!u}X6#XvrIX-tDRhwxWm^?%$ zMC|){$FJ75*QN|NcK>+m8%S=JgupJ1J;;AlBaI$J8S%qj9dn0zjw=6PYdn4?VD0*T zj%#&5K?3h!>sjW;nO^sTrt4>zW}rE{0q~1BAco{Uj%us9W?pWG%pcA;j{=v|C+#KG zODFjC4M`|If~qAytHj3BwFN&BcXILdB#1N4@<}k>x;(SZJesJ6eqiu*tJc@**Kd;r z|EXJSFgFu!Dn6xw$9KoqyOwy6txdK|#yvI?wJ*ln^*JBTEjF26Kl)=LvjSj2ph=;B z)@7hquPUUHc`E|!0W*z@`xD@P9JM2r%>W4XGr*ikls=zT5cCw|GwYRtHXGZPo*Pg+-5y8_aBCx;4r5JP`N;Zh&dfy;-?qq{G(LIcs?q997loVV;6``Fwl}#T z0=kC~^ZQ`622HWL;<@1iS-RzM0PU{bf3NKOuq7pGCCq*UnG63=>og?4!*#9~(YWxk z?(-aZ^UHQr$TU2m6z%N7x)3?rMDnp`>Rzc8V6H7Ec^gWNh0;>U{pT|H|7SY$uhJ7x zqb`T*kJSD(*%+iY#5ksQ&g}=(C_GU&qRz12>pkobFYaz^C>yVXprM^e-eDWd6H6Ly z{W3V{NLOY7XX-?XF7~GBeZfDqS0)P!_tV)OUXPut$i4I&m!OU&A$E{Z?$d3Qt@X#I(j`;LpNWj= z?(re#%jk}o^2v=Yzx=nRPkB$XpnnztK0u&_X7IV8JTA4$0rH^`gOxn7uqDfJ46P?n zmrA=hJRqiJ;Sga2U13gF7yI5$m^@X9fPdieo}8((-$IUpjgPL5NJ;V7=3U zyjFufS*31M@<>XxFfu{*Q1LzitlZth(Lj8B;0!cZP6~(zE9+oQJ z?q$@aCQFw9b9GZ8bFN_-c-xahNO|dnv*Y=4I5(&qH$5@SnPyh3Emur_d0AolvcT@k=W1TJB&C;gEB56f!oQCo~oXLtuSY_I;zsF*V^q84ME7Cm^SMr z)3DY0Wu0aY*`2Rexy=8GGmp)LoIT_R8{-at!Ml-9#A}}i@kBma}u)cI(oy)GQ zHHeH22GOfu-9sbN@ld4!6PZC=J@LO*V7>lXK(!)3n%y$Rdr$}3=`bDmf>mal)yfZ= z-)^qEf4ASqYJ00LK5<5B_z1hqx33i00mKWt77^>1QOvTHuS+{eSw#>`K^sjQ<|l`J zI670yj?oaEj*)#jI+d23mecvrs@ty}L}aqfCunWlDsHPHF`Uo~9K&J(5YVN7S;cu; zqFsu;5hs{^@;C5jbUws?aQ!U)Y~E{?A5T?JZB(4X?roXFQo-Od_ZhE3cqSjr+EZbW20G&(OvVx}-}Sl0;R0O7m}J zpKrViNIMYYtW6Ym8nz6anw`7>)y<8sT8(Fvs!UnZ<5nN?Bnj8yiT1sj)}1rmr3)jD zu`oR}+Aq0>ydt?RS}Q)o|5PR$TTzDR$<=&*1NL#5$fp>mk7r-nh=DKEIPkk*kVph zxfTURJbZ7-RbDeU4P)w#j!d+pF-PjsKyu9b`~jBgw4@_i`HHUIsKg35CU^FGdFP5@ zrlLA4&B)0{viR!b-JU(6#!&2wE6vuV4f9=UgxH|(Cq~huRl0}@FGD&)=529_k5E%;g{({Nm1`8Fk4T**tmjP%4eW7+MHM}*CO8)g5>WT>OarP^$_NSi{0 zTG(}>_>u9z0sgiQRg@%yMT4-0+l=Dx3{#tUlt zG>c%q57(AuuJDHOXO-4}(Kv&WPlzNg0Et8Bj#-ZvJyyZxffx*3;Vo_{m8fPmD1 zj|;xalpWs`%4G~=UmvLfmfFMgaNlw&3li&R-VjvQyof9B8IZqE?}V2C`J;xRjwFQV z2v~2YCrE&V!A@d&TZApRUi9drs!U=Vv~0roA*&cq?tQ6QE}esibR@_3iOxFoEz0Nl zuNX7(Vo6b97f3!Lv8q-rt#yv zGu=~%-_v~61wG#I`N)-di-di725f#6x1H0~rda*`KDpS(jq^o|=SOfTruj-zop07v$JdaKG-w zj2#Zm;0Gll5e^al9f7u#b|4xH91&axM+U56jQYv^z$l8nJMDAtsvPF`;9voUEe+N4I5zwG z;d9v{*)yuZ3kx7x4{BfUmQwa1yggnl(94`;>h`;cUHl+YL6X5^4Ab#ot-!(}?cUdMytmKP;rSeR=|`%lzKoqM1fmVf8#8 zlbjFm3wt5&pN$jVd-9U%t`Tk8WHVU;sAV65lNj-5mK=7@!gRaD(D%2(h#mV`W^kwN zd!o5#NlDGdGA$Y_C-WZlnR9*l?L_uZAdo`a?^>^ta9o6nnK^s?!AsbFSmQJ15=%hbH7b+dLlkjIKAELFyE!30c0-4 z$E&@w-{2cv58H??Sx}T$IFVjcxhbU{5!iQPRU3J@Q(f#ny|3q; zH|;L#v6KB}JP7V&QYYhzbGf<9L`F{=hPH^(D`V?U%Fb!M{qbfq2(>Q$4n~#H9wM*$ z;L&nWRu7g$$w_h9cgN+OlhyjctKzgVjMueYfQYzAGj6BjUXpeIo6f9DfwSeDmq(oR z0Lbx3tZ3%-FsbYMaCW@E!KyiO-(xkM=zom(hTIUd!==YH=$rV~IiIk|HU_KP+cJ5y zcjKdpNr`-*a2_VDeRpu>jPOnI>2Rf_iF~#w(;60)Sd^>Dl1jhQrg@S~O(cb=f~#49 zC#0WNqZF;9ZxTCYp&Un1tBXc|qn*d4wZORB!Mn%vcA^bb2eFU@K6K;sKD|`ytbV`; zxnKLu_vMo2Fq=vDLoKaE&o9rMn*$;`%wr$2RZjM~>#7*-u7l6-6L*;@u35j*T9Os@ zMMWVxZuc`dY*&|@=Xc)1T-x!4tX8PvTcXSkFL#EfH`VnU)l1GBQ3X@q^vLlje5w+z zG;5*BR-XI(4s!%bW>itxcE{W3KSJmUJ)9PfbEN!sr@_->A&5HFqw;^@9q4~3*m;o@ zhO}i?a7rOk32sRQdCRe?ja@?TKBmFnYj%~OW;hWHt@yUP;L)XTVeh_RlGv#{3LdFu zc}A}bOUYAf?hP`o7f9#S3Y61bUEJmQVSXpmUC(Y5i-PZO)D>Rl7xJhtmoY)Ru6F$y zi_$mgyDFued`=O2Eyk;!OAM-37w0)v_#$5m=M&osSz=qn6PczfT-Z4akd?b$Q&-$# zjhVe$LyU`P3P-P~h4AmKzs9$|RJ*qt$JeA7SGawPbVllWnfJ@iO?7y`r6PiFO6wvi zR4=wEV&^Ar^C$G)U#Oe=>6>e&eRF&CBSYnm3X-`vQ&w?#ug}i4p1hyz<0JySGRZAH ziqP%vV*j@Q=@cISs}0oFrMS)6lZ8pt{iv1H04$yPA#Pd%e{m4s9m$IKm9fi-Nyt2Z zsA$CZ_2QMxsq1!cDUa6opj#y!o3M#xdEH0;T!n}<|CAH?NtMQa;_S&J$V8RX#lxtS zLb{=V)U(?yn7|YJHeozdQP45)8})#d{ga=_YP(V`6X8T#F^a!m3=f71Gt}LMiQSOWB733n!AJCvSf?&G*Sq6gBdh8A@NFS(<+{ob>&e@`guVaenx%GeO3O?EY(6>=P}dlD-hOTEW+` z_QMss%4N^1QG(`mK&uLEv(dRWzdiJEvnB|qxyj|QTWADzCin+t5*2m@X79YCTj??- z9#np`@Q*}<#19GL<;H%+;=DT=ev!>Cb@ZODO1)&z!d_ zGAx&YAtj4}`s{4e1JXFefUxG9K+QXt&-?2=_76%ENnm3x?(sXkH?%fhwgHCG?XhYV z0=Sae29xfSF<1-iUeJ{_D*^`Gl3`@u!`}PT?a5JPQ|PfoGCdK3h zX~;jpycbs*G?xBrmjEsM zn9D)ALW`HTfgY$4O0k)`t*ZsmCIemP_iN=BkZGD(9cI!Q&61vi4`7V1M`k7x)lIJu zJ8UK+W*_0d&CSd5CYwYYpYi>gZEtb9t`63O{51Vv_l`x50Ca4_NC^qej?6@k0&;5Uhe@A4&VI=1R*ZC=x?I z)r&$b#CXash)k0$V~~)PBuXhVFQ~&!eBM)u@Ss)rV?yS|+~acU990mFy6z_=%mcq? zc*)#Pw@;h+;c9PON~Tjge?gO0LL}E4y~^OV`7v2yHm~jdGDS^GB-`Mw8?!jTQTIdNs1JEc1$hY7}49 zsCkPsqKQR~SI=8WqgAOLLD+~Jpz82Zfvy`V&`MsM|Ie_SH3&2Jf+bQii41$2~m~v zPOZOUXozEHW^Kbobzk_y0QW{}ZPtFh3(c^%JGg&Xph<>2ts|=VetiO$c5rP2qT}j-1@FM&xU>f7br1=nV{TTC^7z6t9%#$E2n{N1{3 zeTIZ+u2GTCFwCz}7Z^EFVIY5QU}ddwSYQh`5e4^z_VXLZehl`R+G41{8$Un9cMS05 zwrBx$VQ@$dLp|@eYv1`0-=;*lMXZ}YHuBP@v~+XY@Sc|cWhDk)E zu@e?q!O5)S+t4$n!vk*`T_S*HnBY1UtX!ZP!y0>KMOCTiXJ7jH)e2`Kr!`yVARpP9 zF1isGH^AObgNK=ZuCU|&?2}QJOQj)WFb$YHbT=ntdtcmGMO<8k-=zF1q8 z;B!oEj~C3R0O$Hjbv^p zXc8=rS_>?F2DECT8DFK=^i{*5t-r#4NM(t(vfMXTKw`D59OR8`e0qK4gG_AQ{39_K z)-v<54RPGDM6IUe6t0_-W`#*KAi$dFp~@YjUddPThg|>MNpW*z^qyFng&F;0(4!d| zw*tDfHfMcqP$g#TENZ7_1LZkl`CV}8ECxPDQyODJTy1{E>|GeiBxcWZ?m=y{7GPKRJAA=)UE}Xn!58axiv-DXQ8M zsFW4jt=Cb_2EPHS+=rrP){mNX!AczdG+>1yk6_GnTfGe^ZB*kqLd`=VL9nP-G80`% zCyltiaAg{Kp&L~G{=3#naAsWLPop(GiZ$QB5* zZDVY1!r6NhNE-9|A%M`(v4?GuoxORtxv!Z*XI+UT(#G6%749pIj?ViB&0g_2khK%2 z4}XMa)-fde*(MN5wSGM*R078qTP3t{rwsOoTs7ckXmqP76s2($Y{P5A$C}7J>=^Mo zzQ#j@%q<`_D$ge!EUpcMeD%oPP<~x{_4O?Gv5?u2)IvRJrQ-e)GHVutjW-3*%U}8i+ zX8-LXmon6eF2C80i|P}FHrfO!>xOB$0goG?cd3}L9*FQjt?P2j5nO1DXF_(rl;EThKHl*48Uk}v!5Y~lkA|=ROk0wRQ!K zFh;~{Zu)M$E%9C^u$^4LY+dRt9f8LL{65uu^}yaPtebBbm^`Vz;(4$HU=R*@JLF;0p3pHk>>0F!jL)I++Ub=&}@hCGR+xz2ze(nmNYr{{_+>yNH0H}@hA~49S zPMXq*;3PHn(LK5Mx}JZwZ)aBgPKgJwHCd1w5F9z_3R8W3yTZ_xMcm?f0!OLu+l?45 z5jrhc>|8E}%kUUQh0&-FWbm$&!wWR2gyYT(M_a|Rm8V+MI7k#?)`joYgpyKL^#tz&S@C00cG1MQf0(o+_ff_)yxF{ z)gKK)bYF}Ne4$Zs7p>>PvnGiLZu$OCZ?j8~=utbK^txh`UHu}&aDsJN*G09MEbV@- z0!bOV<)y!OUZjW4ajFQlDB4eO1OzlR_nez5c?snqBn+a3(Fk=CwL)JUH3R?caHgL9 z;B3?{gf-DAClxC$17)uS<*L|Z*S9CF3Zow^-=8dtrobci72#e7%2BkP2yM0q!woX6 z+%n^{MQRIpHRe%7nZiEFq(VcmWba z8?by$*&F~1^q?D|fm)vE#GE$&f z6QkFhA;|_$Ty?Q0KUouoqywqJRYSe%Y_Xgk^WqC7k>h)<5v1*0O?iRs|73Ts8t;=m^SwpK|E-UR15&y?X-$qD& z4`DLM^Lq(4FPr>q#RIGbr!hI&36V=gHh%#z(zWj*o1&7W9o3n%(Wde*4`6KiKba2c zxQO9t_Pc|_Zrog}*_J=*@rYHc-7udQ2IuAB`{BZC zyz8f?cb3lxGq^MPkGCUNRhsPYs87s~RLC5e6iI~X<*LnZV-@Y==V6zkh)jO(+YjI5 zGISMC1y&>cf@6wVjRjR~jrmqx+v=#Dt*kzEka$QobLyS zcthtV({G5c&$I3eyD((_DZ%a{HaN}DgYM54G7me1*di&9*ImDk@i;9Tlrp>Tkh>f z+4H)x=}^Q~89tJoUh(vCt?j#Sgm&oyIO=0cen+;A3e}_0+g#CTLb};6Jmqy@+-HF+ z6a!Psw`XT$exrnB=-FJyWqaGXjIYocK!gv&iC2uBDdODFHh_l}%WYP73s}sje8j=N?i8K5Vq+3eeX6@R#l#^_KSV zwXnlMGtYB}0=o=P>5T=b_B{S$Quy1qD4SlHnK5yo81cFS|J^y`r@))G6vh^bO-rqB zqsilzIJF5bY$QLrWobxNBvbt279hQy*+}Loo)Y2tHAi^u6Y)7%ov? z+yV-Lu)6lyfh?E`wUeUCRt-LTWy9mZMpdB7q}dY(IDBf*MTLP-^$f}D%l*;Hq87b9 zp%3VJxZoqbbOU4AWRKEZ(LHaBCi#=SaNg{GFm`Am~N+G zzB*v6BH-dJH{sE|{7cfu5iiKQ#fsbaw?W^AbEi^z9q`M_gh$$qRu`*Z&ddcrmoq(4 z`*2=9jh{Mw|2cODisD+Qxc{V-FAm=*PmX%-bis>WChn-uy#gp|Qm?l*@g^FBy*2^Ff8oy|_JUR8LIGOz zAA#X-FBnIwzMzh+pO*Z5oxKPpS4ebcYdxS;;Tyisg_ADwE)o>T$NRET`c$w6KuEl9UYvOO#SpzSzdT;GI7po$%w}Y@$B1&rNdCU zDDD%A?Y%_y2j*w$+s@CxGTapLg%PhkI0P?L!>?#DS3*^fRVEA~FL1VyE=|v_94vX2 zo!{0^TvQmEB^>oQK}1)D4v zvJ?$X(Nr1o4YH~J-ci*33)VpM2);|LU8^FlT5K{}*Wz`X=@LE;d`~e1LmYd-a+)oc zZ)p-90@EAWKsF3=9(h;GU8j772l}>ZBwg~3OJ-BCN zuKFCXT?WG?WHF}wClT2yodyPdOj7Ts*jm|sKQNxcFY3W=~{2eJYm(13gU zYN{7ruf09F3x)*sjZl9c)UsX(LSm(UtCC~XA??j8(whbQ&{NP2#7Y1)X)nenSNLI{ zHi^8123wzxT~vuYlXBB1Q=}D0*u2o(LsZ%-gUL?RDoCXyw8tbjKa{hplGqddPpo{x zXKnPhRvYc9e_li8+kY?L(9GK!!Su)_^;p3akM#tEBv9is+4y2!o%9r_5W2)_<_NC@ zlo-&gy}22>Fr@1xGJLhqUc}WhXNNl`qj~bVn*7|P6TkWI3Gg%Y)0$kHJHEx(MH;ys zC*#5`@AiBpz%wz*2^y$YG-4L(UZs=jtX7gDu=S4=GhdN4@Ic zkt2YUj}m;SqUD6fp3#uS*#U#QM^OwQul)J-Vh{e+pc zz9^j<+-z+`E?vZcb$PSy_uM#|uDBsYe73`uWwvGn%l3i^ZR9mMuiBrCKc2R!WuPy- zBrFPCF9oA6a;a@KtX*$zOZ#&#@?y(8Je!l&zr^20#}Hn*6;`n>RjHNasjJg1wkB$? z_I%wpJR3o@>DZo@h3;PlkyTHI?1br;sy|lQOD`e-lvje{phHFY%*e7#ksT?q&#jL) zosIPshw8rYR|?;83K6_n0D)`xGP{zIv!*2l+H0G3yWfwaP7BH^pAuM1enYkw|LK0? z<9BY6`KN!!8^f|FY_`}<=>Do;X}iwr_8}~*EQ58J@0_iQ9Rj)>OrNQ;Cy5T}Se)13 z{P7+A&!A)IT%oOVAtfD`ur~Y;O5x_wx)AS)W7FJWt)fa&RRQ7`2Y``JNTbGXo3y8Q zmIDSqt@NsH(_eHY1^0kLiQUea`F|sH&zCwQo+`)SW+G7MFIK)Y3pJtqdNfPLtgs-_fE1Q!0#37i!snRAwV~nYfknSFu%xP)~ z`LAV76x=M9XykE!8k45Au($VfDhL-KmF6Y~+?n8N4i|Rz`eO#VHXGCCDR&aIW#Ia8 zR_hDLg`LgxLY1$bWXo~G?reN_!a&sMR)E}@XHg3M)Pm3h@-r>*wy9>_fQ-2mXNWbc z8hY0ka=n^EIDIBvBq{tOKS<1f@B#2ug0yisoVSoA^dQlC8w0BvArEQV-tIz=dA4Er zC3Mw`+AyepNq=tLp!ROr6Tn@y8*2Be`&bzr9A#LnrGyU=| zz^`fd3%X6sL;^K7>3-&;GT_BAR$#>|iQ}aakH+-dNd zzdZ@#I^~%QiLWose)kCG(rYs+4V#T}W&KY<(Sk&n!jpF%Pvr0D=?^9p8SM`) zcb9ftj6!ZNk3N380*2r_$S;i#dwQn|M=$HE}5xeQIm0B#Dx zN6>EJXfP1{)=A%_q7j|)m%^EIa>&q-M`YZOZGpCGTqSJh5t~2NTY6svDz4tUPoXRU zG|wZPr#Z`P@OaRlAydUaJz{Z9Go!nnuM}S7rgO%T)CdKP&^&bRQtkWK(}U!AW9GSG zO*z_Molaf-{NG7~-Q3e+g+)I7L|Du0T|cjAs#mY{+ZH5daXzPlXF5WwBJ#f{1$2k& zxM9TLUf?&-C(VH^{ovEo2SaK|_*^(L@4FNTjz z?tsjuosxx{RIAaNX3U!Kh-MP9q6Tv}H*yU0AOw(iVM_okWzK3n?WTssj~$G2NT`-giCw{> zXzIDQnZmcEr-xUG@F#@AujVrc9voR>XXnGN8LQ}&QpMFcaX8h^%6nzwB<5?-U5OGI zl>&6z&GZ_1L`;3jH5354tdIiYmv1vKy~{dZf%_RvCi@Qp8I~5|58g)IzPQV`GvPM# zrFZME5&E&4Kymh_TspK-k6fTw$JbcF#bal2N79;Ni7gg^l%)~(m@&$O^E_7XL#W$XiglxRnTHCzy`=O!z5GW|XlToRk0SKk_|J)s zTlA}-N_|;qPh+(8T#kd;NtCG4`Ym?7BhO%_E?0m)@!;@;B8qLlTv)D}JK5CXBvmFHZ!(f zAlBA6Yy>c{fm^>f46ijXUX!)x(snJrkp(6l*pl)SmM4NI_;gfe>#awo-vn}jEf#~{ zHP`88zY0!G>kqi^rJhT0@dL~s86M<8kYcZs46b_@(WXkU9REWG{KcO~r(7n_!gwcB z&7Q6T45(b%P5`T`RR8S-bm$}WoVWKl`h|L5phfMaC%#XiDareDVP(kC0hYjKW0sib zZTCP60~w$H#7wdn{K%c*I1`K#H3x~&f&NaGmgRZx%ss~C^@k=kW{}F8QquY1 zP7~{Q6DGp8LLSZ9go=T{FJN2kl6mBIt>#!}N3u;81NrI%6q=A|qFks~3`?%I{vdU5 zO)~!YTNFBi3hB++S4CZD*J_Vmo`*F@AZ!eX4vC!znhiSXxOE>*?=<}GXnLLEHWrpE z?XhT(F1Xe=T~4UK6x=223AZIbSBLxv*nwmkzQ41q>d>GkmCot}c<6%f-A4PgNv}6E zIybG>O@*z+Og*gC=SfLQ{ZolVy(6a!Bs;2;>0FA$u${cA(c)U_-5&3pr z<%k$0rOCCbh30NWe)m;+pX0pPxeNZ-p<*ofgw=W#2j;X?YCtQ}orj$sh{DWC+LM%O<-T zO+v!-cm5N{a$)Z-|KN@cFQ8%fhrFk6MMa&;-m-L7SH_Bir_5Ob*BVFDY0t6O>B6Gu zQ^=};+3n>@!)mFhCVLHrs;f%etbxu5o0eZN<%otp+KZds|ywSz>UJtQmY4J-SD-)xq@3LMB_#I6GO zover75CM+7QBECIPbBhJ>38`xCd|0Y!$>eCDCev6`z$XR$cLRfb2c1{!cEtF6~sq! z92brXCZlu{=UE4TzJElC4$WPpF{nA!3E3$W?R@!g#^gZINorD`Cj>sPOQ@VMylsd}uimP@$kfY<4rs z@@)UMWPpnb=RpDxl6he+DLQ?biuXt}F?J=aSpfG#wEE`Xk(06NMVXFF?*K8yJ>sq1 zRY-|vf*F5@HR%-XGQ?|kv_i9B{qHH$hI)y=t_V8uzqz}ds^$e0A%J7k;nup()U$f;alms)1#DoHir&y$aUe&%d2AU;KMqdT2sW+BUgl)axVLRGD>0zT<}+}x z=8arsw$?0#3)lh8GK%sfE@!uzVb3H;X51VjDoH8)?J{i5;k)|%IOpz|zbi$Y-vujDUPNQ{S z4zChj3NC&1o)+u3gY-%xEDW=2Bs2K6#>J^MX^Qjb)AW+&vn9i7BM9fCDU!A*NI9>X z!6tLJEx#B2b&r+X;Adi-HBNn|voua?NwC4Ps`~lQNXzL^9M=ah;5WBjeoHK0CmEb5 zYa6;=ZeR-Y?tWrAU0+G?$90rfdy(UcSr1JPCA}qk&1AY7E7IBMM*NCZqE!RQtlKD0 z&m2L>l~wU-*Vksinw5oZH^3tDnpLAbWu9HM!|P!g%lRXn-yLJ(>4Z@N#UJ{KY?1D_*SxxhK~W~V zRS^7+(P8Bl4l@|ESrdlzpdlK_hc^WN&Vk38P7dc2HG%;Hb26}&PDX`iT*~kfp~}Q` z=}-k*X5dEt_ErL^YzCUvNx0iyBr)w4&se2XsF%&cvPuX5iGuX-yxaRR`OZZJXfU+= zY>-m*9X$rBhe?RqP;ynZXg0z3+&!8^uF5ViUbhZurA}Fl&*XbO z)egGBE_cbF&c;i}WiPvNtPXH4K&{Hu=LzhO!2gnRaRmHk?nc4viS~X|}+K9OB-b(M zBWnwNihl|_=gMpY@P~fhJ7#V~M?A0;i5Lv{c<_CkKWjBz6g!~EP6fi&Ge|1 z7sNb6ko0Q!cJTfhEIFCK`hAMc+^Jd|q6@NO-P5ll<05Zu;%31BcGDTd+Blm)P1*77 zGC>H-7RK(6fDk8>X#Q_dG2zgHq!tWM7Z`mZ@A%=Q`5-^VkHvj20xwWw#GEA*X@ms> zU*sT-Nzvp~dI~6z>8kcgV~#z)u8H;bXRfbP0f($-NI7FS!shnh1_U08g*oev+jId* zJgabycA>sSw)AqSwMeh@a*xwPat{oqB;!RdlI8g&(ew38OMN4!94Kz?XgwLjW82qj z;t2>&tavu=V&5;9n&}$a^57>xyJUd+UrjgM_E&CsDn_3y${&FhljD`KHut=Rr+dwM zJ_;azV#m>Fj=7FQX@6(y*8O;=)JG35PoBTF`#MrObZ#f6>krDn7lBf=c4)8O+uJe2 zH}bYGhUi)Qsk&pOc{4*kV-3f_Au?R>KdB)n8I+ZOq2oLg@q{Z(|M6W}aP!H(-0jR$ z-^f0;i}2(Zq*n{o-%lRb9JqJn&rNVH|DGuYw#vRppw$%_#Yqk)P`8q5ngi&S=B1X+ zu2?G3pe8bR+qV-77T)scs%vAL8pE-{Z%dLuiefK3lbP(-nO_=|x!8}{Qva-mf`QP= zRLtU#83+TCc`k*FC9_`Y{MD+dC$(==tw;c41lwV}ZYQ|r>X+}21)J=cOk&qPXUfy5 znDa>khBfnkB8-q!GspZMI5_B4tzRF|6&3yw!s_aD_Nya@nA3x!jmV}#^z)I{q)<3#4#9! zQZQO<6QcI&72?M`3wU<6E>86?&_O@Tpx=XNhlR0rHP zo7)vy+Us%A!gYyik=Bb1-_AVDw%%3m+INlj1{Grepq%z2=P^PX4}6!NwZ~Ygqqa*Q zBMA{9^r$Z!t=K>4oF&UhJau`VsQ3mC>ny3kh1Tzhb2Uv=+s_a?Mtl0;_@HVOjL>+Z>X?Xl z=EFI7A^0<+K9`MV2S;+L%p9$Us6)0IKxZYZfjKApcG;^bHhS@hc&E}dsk*DU>G zLBqIKZ^=tn!?d#ROSsFEh>tGRK0LuLrjbE$@&$Q@>A7pTlMiX`o#PxSe$PrBGh z!jBQV?@8^kZ%6`)`#a0?Xhz7TZ3s=#mY}3vjX08`RavLy>5&g- zKE;+SLLPILd1xx2q5bf);MRkKTC$1CPyxOZ95EcCXe<;nJ7M4BD;t1jz8rFwCZw>1Ait-0SJ=YfJ zq$8h1aal{&_TFDEi;fNDRkI~FnZS4w+9^k%Am-NddW99$vHR^Fa!E?_7_ZZjoivCV z(|}~Duo}m5!CSu5lXz`$M@zmmT&OBsv08~KqX5||cSK-2J{n;ImP`p6@8fz1x)3@L zXX;Ow-A(Bz(ff!TXlG!SiJG_;Mk{YyqE3HJkC!5QmaY8`Y)O=BRkFNX`g<~?#px2T zetc}6RoEy0OF~S+Q$ZQ=W8lenZo%O2>?!(J{1D)M^)~(TKN%SoG)>LS>U6%;tm%5a z1?EJSfL!6`)DG-vGf6z5z1e!d#hde(XJ=uP<>tmo+?r=O^s2&oE3R_>V5B+&|IJS- zFd{}t+h~~w3}TL2MmN!n`iF)x#6K+^h@qR_XsxDB#wVtJRM$jY;c@3t)p_#!9^0m3 zv6XIWBAqK)I8d0tBFj}A|I@Kt64M}!a1J!uS)r@&!5k}R>7tS+Sy3{R%w;Mh(5i0( zFjR7+t;jfnSSuRZbv<|*xYQpjD}yrsspr*Klcr5RbEmvNZ%B|7^e!z$4NoW2nhDpU zu*F81a{8dOm^xoJo0UDfjO8Fw0C-5fZTLlM%hBlxYQd-_4{fleI-e`imBNOCpxY}@ z6&Q*tG`!5bS)LVqJreVbdlqy&kPo+eH9WC}BpN<>=XN<@q7fyB-X;*wDIk&WZK=x1 z0{2mSp3z5Y>@FQ=B&|+tCliSfS!nVZ{UN4z7YLCEY5&yti}lp@jY5-C;tE2Y5Y;cP}UmN`A#C5mV* zD&eycIL{nK5zRP1?&nBnYES{gOH8wR@KU}no3aDR=$$3X-^BdW2xUNv#t=+)Np}LOaCIc%<1591NL}Q1NdXppSMY$e4?NN9}QH|QPT64QA zH)HAQn0Si@1DB6Wg&`T;Vqp_!D)Qge=O}AR6Bp*>$I>|XTrCrlADS1zoegn z#1xH*lkWHR^wMj}$te84ph$j(#N~z5mOMJV+b^6fdQr|zs1L$5vc50R9YkQJkNt3X zW^dZ6T0Qic>UnrCv0R1}dfN##A$xN^eNE#0S|p8jEHi}qay&b`6Vx}Kwkoxfg4s`O z=JyIxvvO~in6I!Yu&Qrr#ct}b$@~(^nak_#(oLS1iTb63tOd5emsJ4SV2Z@ug03x$RuZw0cZT53{YPyu zG6hX&#bB-5;mc*`ZjBI{Fy3xqnS#nfg{tN~B$ZbBw~Ax18+5~h7ypp(^i{}Zm!|uP zz7A_2$)?-vcj)BJ7(Xajx^gF&=B|{dqnUjYXQBeD$BXrOZ?lj4qv^~JRC#!AO}M8u zpUKKc^6I(dWMI!qn1(>lN_R~NiTBb8Y8Gqf?n?!lC_Ozr!(5L^v|wqe-;9_E^BhDL z)BwTtTP&qaD8Wx~;O<(scCl4w$?ze&fX*Hw0R(<=6^|m~$;(1s8@3p6ZERE$C;DQP z^BZN+)qKzvth%6an_{bkhp@lzt&g%xbweR^dA^bPw;nPm8;t#@2!U#>ZtUj?^d0wn ztr>#141izL6uN#gx#3)IGzW&1*L$`(7h*HMX5qzz-bSD9Wwl)z!^});bQjEOeivI3%Tri0i_)Q-ST}G)hWCVerJxVg-OMAdsIWR7}+SsI(#hm5dn%ye7mnO0f zUlQcFl!>iEiLMs_1>63sf?SIc-2vKKM3|2Jy;WM{QEG*UP#4W1z!1Pm*2#&LBbdp* z{JT@~H(ujEgo+;_nc&!kG9Q$HRq>L+p^@j7COV}k#H>CtopK6}UXZoK{tf7-;d*>Z zQSSSR$@4W4@AqdQqwY6YSrV|5>!OY!31Cmz<@Efu6~Xej=!KX0&9ObI4c=bX8j|Jf=@T%lHMCSGll!mOU)7buJ zt44-ursb_03RM<+F7h%J+>z{H^?Qu5Idks)-s@i3M{qq%2{_)cS%1nL$7y2FpWQaV zx6jBFw2MbBQK!M>l&9|93VtgDHo?Z2ODR%gO0UqcR_0)q{47J0q7#ZjAki8THR=GZ zB(EM7Imgo1mdLVH`&2_)uU1!|+_Mip=duwd6hYy`GL7@h-1Wg$5{FSqJQgR~k zu!HcXULN@;o2q%(C=(JPcANa4&TC2X&YP&Biqhh=y|XpdNq842+l~7Cm|LyAc&6jU zE_{Yu(LU|57apz^3!|VGzQ8KWj7%=M}V07K=Y{i z{)R%0;XcjNc0edC9bX@P!XsnqD@9-&6hkIw6yv&A_Ei zNI%v+)dHjcH9dT`9#>>#mvZ4z^y$>PoA*Nx0UoNR)%_vWyjUXqpiVz7i zKL2i~560}xK2Z+>&hW{;-y-QF&{l2S*Ou61T|-*GJP=oA;Vx9@n`1NXq7_Z?;`N~D zy={7&GS8LHPjKutEW#%}yB!ByYm}V;uFUU zuWOJn=yZIcNUu@Em&4Vb)$HP(GVwH}4&PI%VGcr2NL5auD`USCHHuY2b@aAfw5FRm zl-u)D`n?XpnTi-w3h~qHx$3JvpOkUz8_*lJIGCP{I681+meBdUST~it8d3(pp}2#5p#@>O=+zf%nTXmX$4%4MEO0ZpI|r&r;3NSLpSyQ3`@=IRGwP(F@5v(Y1t0Da9Zw}}bbSthC-36y!O~+Hf`Bk1P#Ef< z4w(l8ye&+rUvG$C@8QsaF(NvV zd_41)P>54|N4|=i2$#+2)W(g2|0&ij@m~A8)z3?o3%2I2E$;xHxMZKNqtAIKKMTK< zf3@+yzZ!UFojQHxR|@m#8s&|AZ8kg(OSEzRnLsl6{{&@F#Fw%0Yp@-5;-zQZvH622 zJuoeWc6p}`rkwQQ8%63WGU2zqtB{I>IP3$3@Poy&LlQcatxmY(QL6TM3PWz7GZGF{ zL5t%-@$;7YPKo#1oOkiZw=+SBb*aA{Wi`n!)>nlL$0d!X$N!MD+?EVqYqPH)KoD^_ z8mTURo`)XTw^Nsd(Iw5J)*C_tb7A3Fd$AFLRA6`@N@XKV^SbbNyt|zLV}qJKTt0tP<=3d^`uY6r9)c&V`BFNd+p-VDLJKTFW9qtw zKu8a-IJ|FJEVqFeyA|hl4~Qg`CFauCQJPR6kL3$~KVN!~I77&_jNj=gMFimud+M3! z2Un@zLQ|Cs3fWgyBKPFI>XpYvmL2AgmF^X0FOsS+nuKs^mYqV+$}e1lA>~2Vh0&*` z(uas%tlCuxj5%w*s5?`ne5qDJOK1aRdQ}0Jd$000`TBIdTLG^jQMB5(B=??B(aS8r9WC8(m^ON)le5u(?Q_STTNbREJ7$F?ZUGX-6S?(dC^;ZwU6W6cqx zRD{rzhR~v2p20l9Sh9a@cLaAoM!?Wj28CIf(b%}~3jqPLae`TMID4U5ea`UiWFoSg z%;8t5N_w%wQC?C&`hbv~I02UpRa?|5p>6B5tf5zuL9;e;>zVIxkZG3wRo`*^T(Se1 z`#>!bh^2GMHt})UT=gmFZ=EjP9^WJ@AB#A>R`sWKJ29krXSBQ%di|jAhnPo;k1^=6i!DT@P{x$A_~kE7 zRro*-410_{xjZbh@e`f@(xHYqAOSBAg1)Xc_stnxu*mMiu6-!nK;!2*7C z6E)ZdIv;1(r6L;M_w%1ma_B!D-RpzZ#W>Qj2U)uKBR|K6383u8m@L5>rKI5=bJduC zvfmH8W%?-yzN1M-6dW+WKHBUd(`?USPT?jyUYJ#c3g##}9!yf&fBoFPPqdxkC!7sF z>mX{P3NPvSz?DO1o7mv%9Vp|2{F+@R*DV9voO|)=+l5MfPl5qQ$e+m2Z$0gB=(lvb zIYJq~W1~!JSTs_&&2Urep4Y^)i~zB`RO4}TmPXiJ~0%G9r2c4=hTM;&GyX6^kKm&54@>On=|4q ze1ACn)o|+9A}>=3+Yf>RCzcrc9P4v}A-0To?Ycv>1tWB$;BREVT(`PK9O%lK4^+VY z4t0D$hiEz&`QHOv=bV|xmGN2ovd9Rei;hyZIuQ_It-3t5H@5LU_=sz zfqH;iZucVaRE6bU`13MW z32;XoL+|=5R{au#g$u&A_;(%m6C>5=c&?uhT=WeV_jsSL@}uWG!X2~>$x3@D0WLPSnLHE&oy7~BFLJyLie#O5nzCYHfA_60pnNgMF#N-T3P2j zRVF9(td7`2cbp=?Qzzza?yR>fqCbaFTL{aOK=NAet&QLp#SRa@jZBKn)v8WjEdgLz zu*zz$BTv@bhR;X9Csc;#X7IJVtfb=Bnf1oAI_|;WS|lNm(v)Wb6jAhB`?^{g=VxY& zFqxZSXTHCwb;NEJ`wvI=`SvAsil6V!&WKY}EEd7I&uLYzjNb-ZqI37{Ss1|ze<$}R zfVg&uA^qp1B(7=zT8Ao0iO6~-W3IID9ux^#Iyo7HP;*zQsYMlr>W7RWkqx@WxBld; zxgy^6iHnK-wLBYgwdr>;c{jt{Ow_XKJ_X`N-;knDXmx1hox*>+Rx8+L@E|PYN@F_x zQ(g)*ojF+&=0{#}aB&OhqZf>VV(uC}t5-hiZIMgW#y>o3=%P7{_+)2Gr;`z#y*(Sl z$>dotVO@_dYStOstp+K6gr&vJWL^y=1F;xIsys{800Udyll}z@gAx02^W*#iQzWqx z>Cu!5ku5J_vIDSRzo1IvP&vOnA%X_QbMM{pBso zL#3ly!w`(saJzIvM<@f~qb!KnsPkVLDViom?$Ysrd2{a&7at;yS6d?YeeydIqGRt4 z%p1hU7_JAT2QlpBxo>NAKrPlKwxk9t{r8PfbhRQE>-`;l(>Az^2WFQ&xu>n$%?EU%O=q^)4xg+xXk zDj%@G=841+v8z*kxms@V6-`@eaFF27gNUlUJbt^Sx@@q4$*vO7>5;U2+ROYZkY7}b zHsT*J;-L^E3=*!uCEp+ChZ(t7L^H7Hgl56F3lXp_WC2)W2_4>CTlXu$XRMN~6-QQG zUtAWIl*FYl%+PiunXMh1N9N`NmR_9kP)^22&LaD6(=U1{2Zy+4)Urth?e4P%WW4*R zNw90%74W$pMgozzEiN#=M*DpNu%>MdvzD zf#+v35IDco%QPZKI|u-SApiNVS^NE%s>LQexS%K!fzmA7sc+BW(eI){34%Y?yHo5h zM3$i2B+u@*c}ReoGF~KQ*LB)nUTzCQ@RrrF0ua93BAfOV;trWx9s#1~QN(-+z0AXl zj?`eWTUCIcDc6BhJpLQHa^ zE@RD(L-8Ry!5c!+rFJYAJ-tj&6}S5hbd|_}8oyJMJKhC=I{#g=71m6xYW4cp#$i;= zA!&J^QfM$nG@+RdV1!N}4M^T>P(7L1%R3}qT$yq-7p;(akz?xfD&o2ch%RjReL>C& z-@2z=>iE6Xb_v!RL)Ofa1MAS1l!nMTwxbHS%vhCNO5*U{Q?J!4UHnr*{_42_e8@n> z?XtTu5m>4-=K@w#oPa%(N!_9orUBewAtlFPbDcF4aN}$gc$+JbAN;Hr;$d$iK0-}I zL@|PdH2>XGahAoULZ8WyD3LBEa<{w)o%4bBhegEe^=pQ1o0USiUBlrEDaQMLUs?7GFuH1fyZ9iSybg|OM>O+U6nM>#dl;2Iam;N#li z%xKSzfM6N@*ye$PMEF5@b0}NIfgvl9yVv6!Z25VS0Dftv{4U{Z@97ixK0T$q+)pC# zKqRwQ&A`JP6sk0srA*QS>uPs|>h`6Z2u<@r!E`#=`URBL3qlvn*F%5g*;Nx<;|TQE z8gRtAt^Il8oTN-_e!C+7L%8uwC|~b9dDmS%l#Rm}tr-n{xE7l`gcWuFVV@T5rL`Zl zgYB-#RQTDQzCHxDqkXk=^Jc?VglYjKdeD~0lYZQq_;x>$X1c^-fI~ir$F!QvYM5() zxFvPbg7q5OBj?r(J%GxNhWB($<*(HS2JShv_aCh^gj4*9ZSstMQP*xx(QRUxc*BE# zyVbukxv0n$n}=hqzYb6prOUZocgy&f52Uc#cG()fTU@E+XtdGp9vH2<8VUy{fhjl# zr3K^0WP3lPK5y~&i9#0m!|Pp1^M>PL#l3=o#8YowOU`B;Gffl48Mqc`jk;%W6 z+^J|k_)?X^uq><@!2?>bUUnWmnXW%N=d=|gfwRalRox*mwBXK*B!yd)YwZ?F0}H>W zY2(K)q(#E4O&|_Bx|NsP!w_v5^r2k4gLoZs#u%^jTiE#aT)H}VZ=$A7oZfqgWesg_ zXtJN^7FZfd-nSA*9{^Ag{Zm`s*PrQ*r@c^mI+*JKFxq9FNAcdlwJ;!^F7G#`S~Ffn zy2qgL^3+s;OLNajbAl-{Y$E|*3~IscfB4ylOmT-BMlpd!1!s|xty~d&B+}!x#C3;5)WdTY|VN^dQ z=$uz?w|L8j7oMMfYJjVC2m@)-Rq+vngcqEloe7L_`T+J)K7t{1l)N9NUFgQe_n8xx zm`QKgTI7YI#hG70;J{B0IjyQ*kBoL*LrA?LPrY2x$TDJ;ihBA=(W$bx8$`_rE&dJ? zKQM_f^yv^r#ug$1n+TxIRHxS=>BQRNFvsaz67~rh^rEk;>vQi@u`&&XpaA4Lu=t&h zVk8a%?f_xytbz|m`Ei^^s||9v1nfVn?=etKo!LJsCo@a*+jOBuLtn67iyh-5ZbDx) z?e%|E4b1~;4!+?Dp-F&YWu@ioSHzf8iJZrh@IO<>0B8=B zwU4S-AghHYTw49_k#RPEU+IHB_OIUgf)DprNN|qqHW85cnjw(Yw@z%3+V*a%M~Rs_ zwp>)D_mxh$7eQOz-cW7IFrX+lXhI)ucQJfiy;m^gRJ8>F^RV5Dfn10@0>zb1$YpJe z8&RZ%4+WNuGt)xb|3r^_^36|Smev0DSbm)TdF0e}-h6m*n7>33p|EN z0Z81^u{X!)jAOrl)7dZZ8H(`SEo(yA&*sm@Xxxkcyg+SGRA6}&W464(|Ib6{_CbZ9 zO@8?hz#0$zw=U@m{xDjo@WI|(a z6x*x$UauILN>i$xvnzS?BC3ldn(mi5w!nBUt#pTSqaMg|XnPlUo95+m0>3uHV@pZh zD6PT-kI|yJg6xjlIggy=kweDfUY8>av;VNt{@XKiWhhEEk?ocs1<-bIWH@2Wj4EIp zt$g^n@)nz|?U3s7#FcDOSIq>E#g3f3n#zW^3Y{KH(SmIUu>gy@iZv>YX2S-{o24M$ z;`uikcQm>%lVYrvh6cOw|5^`xkOsCHiCEvO)HDjg2tqqQN;Fc^DoJ0r%WcGj0dgLP zzi$^vO(_3Gr^ADO=YuCh;iuY2f6#sJ`s(pj1q_e=&-&t~j4@?-MD=jdWqCaR&LwLl zbJ{*utR;*88}K*ets3N=MZUG?@WFqYcRUFb+AYH?LTijNYXOuY$UfiqMW0jX^sf|} z{bTX22XTB5{?Cx!$?eFS*MvTlz6!Aae=gsD*Shd8@ET4f&^zuM{YFp2rmtA3U?n#I z*ryvbuRojdGr{-_`GF3N!C&;tevM=0cv&8M>HM7r_}g+1&g5Z=b{P%~FjQ1g5IfOr zP9gqZBl~Ymm){2tr1pVBm#{2bD}PB4Wm@=dSI*|rxi^cU_s}lQ^{XhE;Cx{g7v!SH z;i9y>?IbNU#t|0wO=8ZORY;eBnV9gRi^sPa1K>B_lV#EvoB!+0D+eBUkRX_z`qqa& zCe$8Yyq+4ebnz{E*FN6OoBZlwRSZ~#lDhHAh(nR@KEcLFgws(b4Kk)yM=YPa ztx*wx_u+>(^uoZq3`iAmdhO{N%zKtJpebZn2OQv!rmI|Sq6XsU{?}UiZ#?mTaQWRZ zeoT~iP5qU*>NP@q-*lHW^#;Z(6Z96Zn`Jn_E9U(T-fao7OGj3qG|fS#wI?frM>Z&a zJ4#5i)#Se##sA%3BD*paAsd5#i=)RbF}pFvIt)kcX6M^4D8pP;vN04~!L6g*N&)?| zuU=iz=+gBfM{*9X$y$yZ;haM&O~Rr0NWSiV1#x<3K`e+>I9UXg!8s0{Wa#1;Mg z!RotaNAiwE>Z7h~n9PnMBmk2u2pnE>tgIs2{xQljB^3GSf0uX>;QPg>dpi`DOniTs zOS)sGvYhbycvy(T*JW#v6cGw*SJgD8lhY+rg=tvAJrNROC3yA2xn_*+8%!Azdmq<&FIYCfm@j0N0k^Ql?uzWa@>lBPqL9$bg84fs35A zwG9@a+5DrMByscmu6~bzfV^dU*R;+c4eq|`xvj}-lxI{mBrJWoa1`nNS&@)QS3YDX z1>!{CD?hqHm-gbPq8VInyos{gDA>%x+#iFS{9a^4xMkoL8ccQDaol^(eXiD5@1_OGz zt*2nEEKe)tXh+xKI?Z`cZnG-h%NF{sv?4sVN~!V3b^cDR%I(j)s_ZQoZwLB0D@mOf z`;KZ~TOhFSu;Z!zMY~R_LObl;ZC*~!UZmRm*FEHa9+v-a8*$5Dl1vT(5L2`&aGFvq zr%dK|#<<5=DQ!*VO9WlxJ>wWLTBueew3|YuK;O&K?4$nkL_$WBUd8oyqif3EYh)UY zlUm@BPUG1oVcYlEMM42aY(E~#)nBCe8;nc-A~2 z_m8?WF^j}US{jw;X;S;}qn*7n?GiE}cR)^sBV8?KK@n~6>7L>@Ll@rRpNEDUq{YQm z5fo{bG=_uybs-u9@1mG>sLDekwXBip`CsS;Nl?Blc+m%`d%~;6^oF51?hMY_)A%q_ zFCNqi&AQspVngUf?ZzQ(zty?2V78lU_4thdXm+NDTCR7oOLQnpIw_80A8l>g>_shg za35(Ib(l2zU3wDo!i1%kzeim6q^xIbN|Bn93MW_ZJ3$C$h5T8`EXVtj{8AgY{#Q(9 z7e4-FNc;NJ-V413SvP3CI}8cF?yBvPkaw47fXZ6=ndM!MAw@-gJ1!gOZX+ls$9?{( z32MhvvXM=VtA*{mk-S~!?bqXWGH(p#;fE4lO|le`-OPxwD{r8 zA)wOFTi1O9RR?RV8yA*!$b#IG2q7<=!yCc15XToI(H zGyxT*34&A+Y0{fW7nEK?6_h5uCJ2atNRuwTgM{8&qVyi5g&un72mwM1`Hkn^`=0au z&bi;~fB6i<%-%D5?X{j~t$CK2VnD{y>dR}0hz;e#xW(38XVfDqSaP4W9`0Be!sRf3 z(!_irm?u%ra-^9~;XdZI+NG|IBleCIBMtb{|613PbA!82@4-!CNZ!fk^{EL|p_>Y= zjuW4*@Z`c|_u;5HZSWE_^H)6UT;KlTx@t=#w%t(=*LIS2M>@4^_O04#qOJkjI2^x-$D{E5+n72|c}iA=l5eVvnQ|kOV)+2f&CBv@83i1jZhe0SbZAMe9%fN&+C+P@(kA;|{c(f*&GR2|i)w7Tx>f=t zIIjoI<^mb52?OQKsM}33q?kM|r=GY^YIBa(!*1NM(KJaPF5*i9^@esP2HxTy8NKi7 zXn#rcfYsdk`mo=1n)vd^A3G#@BF$%wyY=K^zAH{zTrkJN%UkinJFfZX;Uk}qf4+(c z8_!YWj*M3;l3}padn}Otz1mVh_fBD-f`h5zqo7p9j5`m6_1c%1)aoBN!_HqN ztxsA$5r;sv2@4ba!Ybu#(7S4LUBg@T&c=(U*)?8{kY_KPBhj2a z;(GNL(hbX*tI(kZlgqsXJy6>h+$S#IGTiQ|hxsQyG|=UkhgC3LHALfr;%SdKd0r-! zIz*4EQ8lBm74heBFjK~~SiQzpOOO}{c9Z^j!% zkNaRPCPDdLrmTbQS5^|Z_od7=Znp0#Os;PjeEpeq$2kYaPl=PNGh!W@S<4n=nfZ;j z@IB~eZEXjxRBgkUZEnj%ZBmeTI(ay)82&oVS|KrdzOntrD?mOH*ZztA7uh8WV&($p zIlKHPuM)Poy>6tx=Hb_9{2G7jQ?Xc>_jQXV3m4uzp7%IH#O>hg-5y@vzr~g)%t)iW z3Hm(s8!QLuG4U^#Pe$$AMr#7S!85M<2CW(MUI*OzmoJ}iu_1HqVjZ&(Ro88tNWH7nddjgGApODx_ZES%}9i5BJE?1`Wpzc)tEZkkHMzz)Lr2=Cv++ z$%QG<8y6hQPc|w?@DR~TMos<$N;45&%ksZSB_E;rBdBwXWubI6L#6YOPu(E!0%)pa z)LwYg+{sB7Cf!+P?uB#ICWg!64mjA?U4JogU+0A` zmRTr`O&Z<6QzSNE*>RPsK3b1W3P~QIdO(;Ti*r1)jPG-c?qg5xzZ%2k{l$;;(=Q#; z+vh=#+tUg%GS?^PZ0NV`ZVH$PH(ZVV4!;`rVeE{`W1Ug$eN>{!BF9;h{p-gD^j@Ox zEjpgoibkQOKVMJ3KJOs&=!f^!z3V)W5by7|5_~U_h@<9W8>>8B=@Ncs9_g{@H+j>< z-if{|ntoaQIV6>-nsm6?Pg`AwDKdv5_;z^eL+?0(%TNT%TAitln68@)#4C7+J<$c^ zpQ?ZNIqAT@afr_#9Oz#EZL!m~#8MUHSOcJ~x^S4liCIXWcqa;ocdMk$IevAgfh z5`xf#aW||qzGE)Q5yUAMWlP*(W-2GQ(fHotUo41yXrJJG>!UsN)yv3=K!Q(vS^cDv z(nndMu83sxs95cP)o%r0hywzH!_%eH1SJ0u4t|GU3*cctkcHuIN{90W2Mf`Zfx6T! zzVK1-e!@%0-&#n|kZk6rrdfV-ul6xMyd)gkwdKM~u066TZ|vkDSVr25eEzoZ`LpO< zjX+4erOTb2A;B*j%GcvW-p5x+a}Cq)jWDp+zS>!&3Yt?k^9JLK65~PwG$$e?p1(by z5uVi`s9WmLFS;~7bX&P2ZtBC(6-R>oriV@8dX7h8Bju@44=Yi;@bnuUm-N@e-?PC| z<4KP??QMv{ci9XcYPVOIh(lKuDLuYxLd7jvPxwCY4idMD0y;fc2#*xsT~lEVJNNuj zvaI-)1Ek!LbfCm}i9=RWQ7pGr%3~~Qh&V|pi|nSN!by9P+T|NI^Gi~4lRwmZ+4Txk zzu*hvI4;b|ef4o6TrY;HR_>T-2h$pUE9dyc)KaCxNnS+!>2Zj}*>dqz>wUsFvLl~b zqTFft=(1g{L+h0zE6gn5+(Z$Sk3L*@d&sGI{t>R52L;O{P@if%XJI@=tKI!HRxYU- zzZ@<$jwS2+dZ$bFR^T(*K1<)^&#;^)GwE&H643Gcw4AqZ9?<511;ph_<#>9uF17R9 z@7%u^@-nBq@Y(s{XTn?W&FZ)*Z@%{2aa6f+d+he$9@#^o$$jw{-XSbu^xVQIRYdcP z=g+PBAmTR|r9`q)>H7oDVXV;Rn0$Q#mnO*KA(T>EJ(%OYO~8v>f)KrlWdmB3@p8;} zqxVrl7V{O%NoJ<)nC5Z>i+SDOYeOKROXE#3Cu@B^59AjjP3f1BJ-YRB z#1&s-zL$s-uIQBuNm_KZ9g1`hJ}1;2WsLl>!^XUmM(DVpXf{?7B|m(Bww0^7ZQYcG zmiVd%H3LyqU_bF~=#tjMh8tt*_G)R=j0JYo)8F1*a!k9i-n`$?HPJ>zi9DQmsle{x z%Cs4-u2=0bOsjUct3b7m<300lb+wR;U?3Q?_1*FzP^Q>Ce$gJ*4-ci)q=d=l@^F*R zc=|B=dIHH*|1_1sLWoyeJy(U$tlKJMQKx&jw>bwU=7iAqPB+{Tepr1)C2<@>8fAudtD@U0+TVW87G&f#4IapU zVYk&}yOnh(< z+{ZL491;-vUF$E!T-0^8DsRN@?$K4C7%DrwsXz}K9~W6)6622#bmNQH4pX{Q9Qv9P zLGlF`g05b6 zShtp&4UtpB<>r$m8g5ae)}IECfpw0mW74KOn%j+Ag+5~5an|gLCIm?`*dIY(Z=PQ{ zusl~YTs5(Gzml|Ez-p}I$UU(2$1nW9QU(`xB<)fs?MpbsYUWbXA`uV|n?wY8*{4pZ zP$isA28(sK0s#CK&;A*rxn05K#?-y06xxEkF*Ub7Edl&i?2dKq|2a_V)9vT^g zlHF+Hm5Ws1?E`wbyd*}HKbaLh0aTiD>Sdiwu}CvMMwD!?a4!^p;|o2T^Ft7OV@TKq z5a_RY^;0Q!Glq*j@9?uu{%rq@-EU?6OS|2KkQd8?A&MYL-Go!-_p&d9HMbP5fBE`T zdXDy6$;_7A-CT?;!cj4k&U&AYZj&OFvEQ9uPoPiF*I(O`=*T_x&P#6(W%xi6>(Z=yK3j?FD`-jrjdd#i@^QlP?5Um)UGy1TqI2 zX!Qqj{z&cM$sfV!AyOZ`+gNz`u}Lt4Ebu)E!81zQYlNiPB%HTtyh5_Sc;J2Pit;@@ zUVG3dSkq+;CzqBQYkDGp+B0lCA!11nv`TlY-_z)(THUP6Q4Ma~?Z}n7if;3$+DB}l zxv;T>rrmWW@FP#xeDoN{@kyO&UB+}1xB~SlGm8d7Z;c3Zyn-&8eQPLhS9NqLMb9xG zwP{Sw20@svPj-8pCPFiy-WtB*FQj0tn@2|D{E*A7yE}J2mFzc_Hg+5M;t@3! z-4QnQ=p%R~eNdF4Yon!hPgt!`cFSnZqx)S{Pz!NU$N;o$YU#WgpK=(~Bvn^`u#GcD zHb&5VUD+}ZDHZz(@mSK2Y3U#9tH2>WYM(l?bVFTUri#LQ5lY#Zm|{)W9ki>x;Ryw< zHOj3m1%PEf?yfkMC*0NjW z;V6&&{Hkhv^T^ZTVs&?6Rm^uP!{x1S?Nl+uiK8_fo$cak>?F2xr+SavxYijVcLF7= z9iL^2cj2D?Vb|E?<8BNR+Qvdb+wX-;&T;#eN7T{^put%k^;ryO6fN8uZ_y~#=x@@G zIi8e6#?Mr7J6#DWm7GH%UHcHfa2u1OU{AQ4} zENz31&ML9)O+-)bvRn$d#$N8Q!gc%UR=Su>P>)2< zi+c=E+5r`9+tG&{XOdVw{$p_Cj)PHhQ|nVb(P;|Rm5ao)ob9BVD*DUptPjY)-Tw)h zhH@Pl?Wh=i6-SJn#L~n3dvQPR*wpRsy})|vy*AkK)X+6{aIZ?KztEfVFc{lPoWV~n zrZ(u_Z-UwJPe(WexgYtPh`WxfyMkXGT8>Rvy)owZrALm})k=64ZQh^88i_O|<2E`E zTzC9SED~r+XOEZ0@zhVo5M>S0)54DZcTf}!;SOkMBP8?=^3#m9u4Hj-EC@O2DMk*) z^%_i1W~WZ_S*LC5I)eD$L+X#*?P6LA7+fXwHa(3Jn+9D;Tuow{W?+LSGv68np7c9X zeZgs&5Z5ld-57Fvf;4=#?^fs%8{;aEUgU z_K!vm7F#*&YLode9`j=95s$7ZES>$Vpt(ZY*yjqvxRRbwZ|XIidtD?&51u<>GMe9%j_KIaT6@G+gO;g@)JL<@w6&c^O3L z?V#QH&y%X!xvU*F%g`>K__e9?hsBXh8+BqBFiNN@l_MDXNthq4+U1yRGhAyN@+fVs z(EE)Ps>!and>mINKdzxG?W^a{*qP;Ptu=VplYex7>1FRmqV`6KZ8hoph?L6s05R;uLzjODf!M>AL&~E;ugI~+9{3CZw1PGgli#ux>b3=3t z8XOuI+mX#MHQI1Ba+ea(SBM#RIlT*`AnAdJs~F(CrNt3 z|Hs1o@8x%|R_m$Ux_QR=H^mq@!XP@k=QlIHu0kMVwl4J1_AZ{VGH z`tW~Q<^QtwIT;9RePrSG##f(_{+l)Y%X$Cuvs;r{91nz&|8nU6`O}KvG9gZ_p6v7G z|IOpZ}im zr4KLvbUY6zWrh$Riof6bp9}ow%l`A|?-|p)e@FJGOM;Mqudd8zf`pN@wHSQ0j^I%e1Y8sdMv>|ZM^ z;P;G4WkiGjqZ|46QCblM>?c18{leI$r>b}Mz&s5~(VxDPl%Vgr>}#su znWWZj$O9p)TQy+( zM*1pO-MOY}x^P8Fk}vN5p>@1yBC8`Tw_FPOkpuMz<+La>xX6g7% zQ)|nfx^EaJ@|g@LuvBePB|UZj2Hx-Kg3Ql0VawAzHT>}%eIb*t8^#`v72|t0kY!Fl zWA3VZo-+bgib`U$UZ?8?JRBTdH>B!wgq-FidhZkb!E%qgN3ha2_<}t0U`$g_Khm>^ zNwCK=|3t*2%pAmHYR#L*4h#HnmQ@NJ41t_VC)Q29=DU~;Kc_xY6})!mNw?I+T28ge zP6OJM6*)hq{v4a$i|}tIv@Hl1s1jZhUMs ze*Ox@F=j(tM`t6u7Il)eKZI@7jt+MQx1u+G z7hr8;L;prQgwdyvzs_YvB?WF40LE_DT{NTaM@{r63vS0Koi^}tRF?<;iEZ2S686Sr z@;jTdp7*oEr+tV}Olgo^dB;biApg0uv0aCd{o<`;PuK04wzodyxa4qMgUEf8JVaXj zMFQEq8(U`B!}Y4X#sZY~gGc8z$o)f3S;%60SS>>8Y*|&)BfEnsO6tf92IYqxw>ma$ z>!t{R8(V-9GGUA3cjBdXNIz@Q|NBv1BJ33o$WA7<`F?kW6@T;tHFcl}pK44sHcCvX zT3A!tZ#x<2LjG!Pfnpi#;k`avG1hvFUmdPUU-SS`Z`W>%{41#|`JI%tE(Dw7B~_RC zDSlNo&j*sL6STBO{|Lf4Th0O9-`7j_gwj=!MbZJyf`mElc{Pp>cLd|jls3P`40HHDGqy$>d1!E$C zeh+hy({+wr4HNk{Q`KQ(-*lS37XlsSt)(xHb94${{4nxGH->=^eiHUMhcg2GuB?Gm z1ZxDXdvB(kPTJJwh&xSI25(m=iBG>yk&u*263I}eY9O-nryn4~=# zFkzwU>h+O)^%}7%^u%IExI+oe2!oKlt?zbA-B=k2F4Gb`2*w2lla~OU;KyqnjLvXa z)HViTGm#q>Yk&Av2m&L%=k@|7xk3I!`+4h!y(Nc}N^4jgbj`hl(f?e)ce}>iV@X}a z`&salm?urZ#67-WCY}PmJ(}uA*gW8sXZ-{J@xp^Nj#SqFG!T_41iQOJoN>x48>uPpyYXw47^s8y$~u8O?vj_})9@@Q;tnKx)+6HVB(F zL$Mfz3+A1W8D4MWCBl{B3%|TKr~{Af>1lHQ<|L<#gIzd&&c|(cHH0%ue`i{+#Lya@ z;hCAX)$Y(DtT^L)y?^& zfOshR%Pl&{npVHUCqkIm>gX~~IuiF5rKH@}UNo(DGLYr!6=`?)U}4i(9cDqrR-lj5 zcB%MoD4i@D-AIzA1vA~f6`&D;Xi0R+bob^`{x5mE}w*0v(g&T~0tF&iym2b}i_IO8BfWM`N1}kr? z<7AXVRYR|hnc9|yG*rzX4jn>LdA;Kl&#sHi*ovV1V%3u+Cg=Q?BK!!jC?>xl3QfKl z9XS?DC+fc<1t-_{k5UwysO z0tcH&1fy?thGs%0WWqdT@@tKq{b-?9zT_&<0-Ng$>!CRrK+Kq=FSLHLtQ^~%RCZ!J zv(LtiAmFFCHIH^JpgF_N**NjfaR_Jb5eeWw&}ba=KTx~1+ki+BK{x_U)y@#){A{}1 z2gc#|pEaFurg|+ZUrgk_d1*JBA7LXl)Ub%smj#uc7a)>$rsI^Z5d6WSFL$Tv_L4<; zM`CxD*c*t?{0tUVhZ0feO(A?W`9gISFDVLFdAE@bWYk*){O7ZYdOo7k105@$Ov}7{ zvrO)R&fhhFD2Ey^YEuqX`gqT2qNLM-*43J#EH0X;7A1<^uO@QmVDL^=WXRn`lNHtG zgg%d8@tyiMkC}>jkIU2;Yju8AY`rai7XAW$xW|eO*T{vfEr#bfOT5G5Vv_LhjUK)0 z7cj||;PvpjI6*@ZV668KT(V7iZ69CL44U7dl8qX(3p-=nbUxqHYS}cFM1+<>95 zfVJbBe6UBQYdWi6RDCAB(MJc1eki!KEuba>w-zrxYL#o)UuhPFtYnl`rg=;~uWuOEU;bLA7R!e*IXwD{*p0D1$A*>HzGL20lzr=t0`d$T?erX<8Phmc ziwA!yG2PRV{1KrXe*g7g>YFLytcI#Nen+p39uA!Qixx0;vaWvYA;lkrC03#VtvbWJ z5&`Svkea(3B&urTTH{C5>$F!P$0cc1*r&x`aaDDTdW{Na3|Dz-6Qzt-+fSOoebx(Q zn5CVJrI~%S6Mr>>G;CP`H*nAD5cjJM|NL}#4#V=i8@4pqbY27<2l?$0#abVwdCsnn zG~V@v-rIrh#u6FqpxpI#{VZU;X}&uRbHVUM1Rm{u&o8?CE*191{oXEQ?h_j*8!d8nojwV z$9|-97&IcPH$ObpeSFg6?4IW;4Myj;I>65)G(vSY!FZoo0CdX(*Pj`X>_<%Y6DfCeXXbi9W40MKr_?{1aCp7fkq&a;Tcf|Et}&GCpq_E)Np5|NjP zc!i_m{l2|`LxMO}EgA@McZA+f5YZdk0&);e{1zGS{3xb9;kX&tfsOd)apc^T%r8>|$2xd_JfhT8%#3K-TTA#7f_&geDfk zfbgZ-f$eoC?`~C9AtEa3~O@Ls{UPgDIMooMh_jMGE9sug*vqy{M{0fTgh3cEa`N7v? zA879Tjw>aT#;DN78g&)xcic?Ckg6|>$9Dzjf$rVOGXWp!Xh|4Y{hHU)COf761!5BG z)r+OY-w@x5hLR5dk)3{)=_Eh35&L=Z)!U^B&LSbQL)_=u;dC^ge0}Q#>tBuT!r3}7 z=n9iI2}q*!xOTi5>K-wVv?8SO_PCk!LzZrxi}#mt+Xo{E5@n*uV%>sT&ct~}xe~(~ zziN-|sf*(QBq#)$+r=~s*_ z0Q|&kv-|7q&W*SDMtRW?Et>z34fw3zN)Pg*3Okvdy|sKhQ!$*5Zsr%tbGPLU5l;Ul zJ2e

    )EUWzcbPrNJh)W=76R5G_eN!UcK{No`3z-z1H{{50d@&GXG9G{KZ!Mptd$P(9t(*@C!O_2S*2>12|8a*v&>Hll}DaA>Oi<=$6W4?oR*Ni%! z#P@T>$UKN&%Wh*I9glvr3lvm9wb~WMw7WUxW&xRKlH7X9A0TGZT|zi)b!E8vxzPJonjn2Tfm z!d1J;N^7=NZp$5{YtH#_=(XDt?Vk5xOPwuFmYtu~Pkm0;ZL$}x`ES>7Y7qV_r@*d0 zUxkpWvdI9C!yOQEp2Sj#Tn4i3hkdY#lAP z?#(qEAn9BYb036VPZM{K+@G#>VCbl!09R(h7=5?2GR7L!8K&Rhq<;1Ea&5QAYJ94M z;V;fOVSqC@tA`#Z@)%I(aXed2&g3*dtzL&E)xRofG=XvLQ~p{YW?ELAPUQf0=IXsA z=>wCys3k8|w0Y*hPSY9hrX24^XweU6R!8f)JvvWt(5;gdSi`Z02;%VA1=YX9=(!)2g2O}jwD2q zKwCqOv>=!N1rfc%9^g&tI|%5{Fe1;QYT>5-U>MP5>Sg|hWs4LMr*wYT&5}ArcWEy? z7^%mfa=4PH^|c+ZclG+GK~JYD-<$BQ%D$XqB6Nlg00|=o-6J~k(PB2!FEu4^=M{t# z?h=HjCP}$yI2032Yw+;VjD2G6eaDbDX~|N1JvU>?o`9h@FxfkKQONZTO8wMlVU(jcWSD} zPBm}j*KRWia+3GzG$&Sqz*zt^?clyKO8Ue)?z^TmZdt-VVz2C%$kJ;1r`noW;<`mh zt<#S4Pslpu5caG)=KgGg|CMvQotfc7h~Cqx{$|qy@a=SW9G}A9t@vVsus1PpU3#V} zMpAOs*SEJNd!FZrcRyxVV?T|%%=QE~XlK8DMjyvZp=}fx-FfcR znkIz{%AJ;7sp6d@&!`YpzJ~S(nqQYUTaKn4jTCF;JgXfK!%+9h59u4$Io{I%Lyj$9 zTE=r<)Z0M}FuVTWFKe9uFnZEj!`8nVBn_9DAAPB@=Xh*422C!TW89unbRSl1bl+T^ z36WX~pYg+}d+fGg^@Y%qGM3|BQ#DS2=7OdMQXy>l4OQFsfGc35-wXl3AE;(+GrFqL zZ!VPv2h!c&YTAVbk7xZiWHft8vZl015Ayoq?~g3gLqv-1cdNe{M4D_se);dC@cVnQ z8c!$rWq97^oL-zGrSa?GB2KX4;9wuc63vE)`^+&rP(j2ahY>fR;qv4a3aNVM>$ExJ z^5C;Zhh)?8-W`<9ZZoD-2dZCjtL9;&0HKOeKhokl>3hR#&HcFTJwWWxAefBy+@>{B zd}j?0HU?seh-5PNyO&8%f!GzxvwR4BlAZ97j43aP*!Z%KN(rF?oI6LBe!1i4s*s8W;SrT?aoOGh_5$XJd!>b zlE-cM@@CezITU9yv3?o`4PUhkGnlmQBvrB>Rrp7oY352Z#99Y@8Oq>}kqy}+f)(Vb zu^RDS_I~musq7JUbGV{D70#>~dOn6TQV+aF(6QRmqVlpIDVGI=eC@E$-dki3eF3`cVz+NG(!~Fz zX7b|>y%Av-AIF;a3Z_!EZbPjJtrA4fC!~+(gZi4w;durl(tm^A(YFaJXP8zh%{lDZ z2@fm{&OCgNCl5BUh4hn$OH+UyZ_l9dTX+(bW7D~Be?dwk^eqs@FY~^&a_9HNuLnAE zY_q`K*0rZ6d1VS;);VUmkETP0#wdDEvt*#S&!m~TQKwRBmgA~dw-scdju%kHmzlo zgK3;#haQ*tW!9(0u~^924q)H-?^iqkN~3^V!<3ZT3y*WoFNuwmEVTAOaY zH`_Sm!^K?OkeuNU$lII_L(UFG>}sYRVHf#^o4ubrIuF)st=6egN-d3t&304Sk=)m$ zKJ)i^i%bDdwE2C7*B)iMQ%JkiiUB~bzscvlc1PrmJ&-xkZ|D82y6rFEnqTKO$d|ayyOr|f4YklF z2LA3O_JJ?9?K*={^_3fgZ|!mwcYJi59b2cXl?SzSXBM#oBB+U0Me-8BA&=)e)A+-m7b;(y+E@0i zLqApRr{gu60{oRNpv>)zbohiSYth(#`XH+T*pI_>>KZY_bQs*B8}gOx%yb>9p7&Wb zf78@3Cd=0V@#FjigHxSr^>EFgWhsOn4UQ+6H0o79m$CK$x_jpGb)f4V7~P@(%D5|W zY;O9k(Rg2DhLtz8nbPVfciqvqoWxeZ%Ypp)AC~eG9vHkB{RKo_Qvkn@^QvJFkccgU zxALTq6>PlW79jnmSVWUy2k^w(fXl~(*Hn)M)NkCTpQdb=DeYTnP(*5)4p#4aSqvqR zQ7dvcAkL4`3XAS9TZRgz;_9v*7T1ah7g9(f?i5S$yO*q-f-=Z^6kf+`c}EzGuWuNQ zPdC0^OuD6FabrUhCI7YR)*Ji%x6xY|6`UQPxkh8g+tEVvsX2|a5ss^p^mlSf!)x6YR@H zAu{)o0We@og(|Uf2dZ2+tbhJy~fXH+~2INc9%F+CeZQU%ySIU`t4qcA?I6bC^n+y;8HZ#7h z0|r7ggXaG4vSkx^97?G6JLwk|iSsD`<68V&T^T(d$e4D)qDaNK^pLzRYiC39jtu$v zSzo24etpLYA66l@J_`<3!;M|l<2baoIvE_xNohKj-t2Yf_Pop`qB~qS8jQD=TSC9pShevA!!_L+L$W7%%cQLFz2 z4gca2;3L9J-1a(%hU=^X6>gFGvs3*J7n5p^**?fqNIp>r2gltyUI<}2^`X9`6vgN; zC2c6XXhC^^@>;rX)aX{E83k9iA7$LF?2RA~c)JutA@xg+XJmzOm15cNUZoYDgZAM#t}SI%7-f=Jr|LnxjwkGN|)~=IXs}^+qsB&yjy# zFjgXsrOtiH`ymXWL;i(rMtStQENl7c(}fQ-&BVc3@*zGkg6UCTAoz>8<21@1^h18HIsW>n8H+Ws$GIA;GlY_#tm!20G6~G}1kO z!(;fFilVWT?9Q2a$h}p?)%Np?JMpf{-3p7>mTX}laFT@okI{Kg3jC?1KRBnu^G z;Q$v`fwzw(VWeoJXLqraRWhmjwE>{B2%ED_o@b4Tt-|zEbDy!*{e{6{V*N3z6u%@UqYPgcHboh9?0VO! zPIT{>AnXzB*fsl18>xa%ATdWsVn3(%EDox>j%O1R&1QtT{-cgyov!DhEsLxlOUy7J zf(OR;zh%>|`1wCt01L8y3!nGD5P`89RgYmMf$0ej!B>X%aH|0a|X1OW;81cq9#sh&g@h3>>7VW`hjy1 z36B~9fPLnb$k*i~3knEGkTc~KVUn*v4%pS$KH*H+!OaWXgz4x- zX7Jel2wVNO>GA!7*h_0;C6V|z8-I?b87~EkPfwd5)JUi??44T+bdGB^56x9WPwtdK zmucA;d-j{z0u^{kHK{MrbnGx|tE9%0aB8XPc2ieZm&>Nb6y|5B zkhT9K&_H*C`iRZt8_KMO=ZCKBQnXODoL0#Id%o(smoI$ply&k37-VozQ?cu-%6twv z&L%qK-gF_Yxl{bXWb7f2Z7HDCr`uw+!vBo=^%$%(3-PET+UuJarI3!^U4o$2Q?ir$ zN|6VcFQE^eK^Ua!QnWrV`GHk&^stHSysY;nvvX;o^n+KnZ9F>Wj zb%vVV9jJq#`yI+BJ`V!d%3K%(MZ8r=0$~#U)$XR=i?ZPsa+Hbnnf$s7m{$lDbJ+}D z!#EncrnL(iU!0MK_u}c-Gm)V;1!)P@MQ*N|h5-tHD}gc#r;!;#Ehc7K5obyV+CXCJ zHkz!A@`e8Aq~6DuaW5p-;$M^X9~OsT)zM9@oAn8=;z?UA`E^6;c)rjy)YiGp9SL$O zNd01iW1y#(OGc$l>{X_`OxpEEr|n8`8?Q<7O8}h-U=u(PXdxLXE%mAbezg~g0Qi^TY?A#u2 zuAboFTT`t@3g$68Yv>})SptUHKKC`k%QNj_>t9&K8HMH^u^&BT^C5{I^VKJLWZ8KQ zo4RG9FLJUk#01W0FN>IZ*+kZ;Ng+D_-p^e-?YY`@3z(>zhpE;g@=54w7Od2yTswib ziDz$#ZsBw$_7@MI;iE6TZF0`5nZD}eJU5qFrJS3>>b;5|fA!}?ebeFIt&v$LYvgN` zBCE`m?ghixuad$H35UkK(@7JK7av)5Q^LJu2r71T28@uhW$)C-#(Ny8Ue)i?OlwF` zn7(LN*{XiTDnXM4rQ-n>nd~;Bb34@u;ai~jNvx=Hp~m6t{RIPyQ|GRG=w0uDtiq*h zmdYNZo+|psS-zY+uR{~ZY$85DynQG|O#BDjEz$Y4Pw2-Il|I*JmhoP5Ymtk_e)1a1 z{>VJY;h06qPrnGT?-9KmeA+)T%ubh1{l?LX=gHR&V+SOcoj?2y2R@Dk>Na1S(m(s3 zDteiZloR@@CuYg;ibGYO)1@@-#rYjmM}7IBsEMw7$gy*B zR#Q?Z6WSh0qaph9^a3Y~o~wPgS1fadFDuBE3L1QQFVh3RF*8Iga$a`54|6H=u}kv# z>E?YuXVU#J=}gr}(S@bF6mu?)MX_N)8-k%HZ#f-F*BLyV49zIp{qmHTpLXQ|ddlvw zPzl=h4nKC4P*U9u02XO%zBO10s>xjpL#k#!H_qkMFsMo7A`}3f0FjI4WjmEHx4Idh zlr->o@`V)RBGefnjz1?DP$p?O81CCAl~bQJ?U;hdGBQ}jCq0x!WbquZb2&i^;d$+T z0&y?s1EKPG@zOiJSr%VJ#N3)0m?-#9~A5(PM-d!>SEus1;6L zS&p95(1&)PeQF00)$m^y=1YBRbcHm4I+Fc}RwUGV5uIKdZd_EX&U=UZEy>+|SVm+x zU1splb*q zhhwF|TeBb8Ftf%%E^GVdXSVfa^3E4h@hSLd&}a@}0wT@2Xoe1uWM8BdVMz_0!t~aen;92-&{hy zm>iKNdaLz!X-M|ZigcP!awL4AZQhlZl)Z7DKu=X+J6t+E#ZcG)7cD$#u+L>nrT7@x z-5WbUkw38WX=%Sq~Qyiz?m)%^2V|y0uRpnvTCx~ z#il9Tw#L-hmPcTn{9iF`G=S4`ngs-yxOVnU4)#?3d-k$q!xZ?{%oN zNZt*qFLreZ&PFTh&g>=D>b@8L8w(kRFD~@JR1TEn8BAR)&pZBW@ zT^v13b8&oqud)$l*kAt8e5T$RQt?S*p_@kD7+~vzUWMOn=OfwJyAZK<37$Dv=?Rftu~9}M;i=!Axo?LBr8 zFCJ?4#(25FyeLQa+3EHaTKg@dBsZX|D3ymZXu66LuL?H;`R?%WQ0JJ7(U)I#cNwQB z61)~9?#70_W8uGR2c>6fYlw9AM7wV;*Nwh}K`B;DWXT!Ep~`&C-;7D96WE~AXIp|t zhe%M<*}{|EeADUsZfip<8D^%bm03X8_#r(TP=rP1zM+9T{AhMsWfxvTwACp0&lH_r zC3hiZ{J|<%F_R#wSv{KA0Wn|ndk}i!>?{zkSSRtI9jlIP$xtyP+j<%1)QhZ%J*=I2 zSbEIJSL;9G(N-RR zP1!<&0d^bepGDiF4OC+ZzyT~G`AneK4SRSj+Uor?oH|#6DlJn23UP{FG!kGIxwbsgodf&>w<9_iK`-D-G{m@q5+juzh zmfOjMtZzJclL)ur-@Drhau*irzEh@|amLC5%06@~@u>QEongX1jd{P8=0rp|ms)ew z)KO!OI=~@S=B6B1I3gMpXQ>4-(|lcW$N2PHl+}p}Qa^mDX#Nv-*%Jc->7!#yNZ$t_ zL)m`trTE>p6H4NBgi&hc9aW3aDpmHzk59#SqS2qcPBeRFJrgy}2aI5TKHR9Gi-f10 zin#JJUoI_ansz_uFShIpJoOD4of;Op#&PjUprp(UmHAi_;n)31ey!yShNNGqNolaT z8h16nDc*Hn5ULo=PwfM@K=*>o%FwTtM!neQm8&B{j=ha@BNDYFsuPnKrTOhOiuRW> z*!PY;QEPV8)jM={^txrVnXAeAjd}a+J@1ZUTG2Ma7SnxWC+|oLs^yLLJ-R(8_?eFE zc^vL|DGL0x){_Ja;VPr*>CCLQBInYM;2o<`8}m@kBhC`l%G9)%<|_>MwK!?Vw4W-9 zCH6tQ)hNlqkei3;s_t<6-kH(5PSzi$)0Uk5uB|PBo%tslO*$u2SLIlE{9esw>#q^- zq4egu>t4B{x>pOY{*y)n3f%!c3PPOrdo}vM$Z0cGs_0`(FL#;3EJxL^8_6z8rH@*- zeVGVx^@k>0R66d9te*$vqw|WOG)ua1fKe}vhqIKF=kQPkCGm@FweYo!HXTp|9s%r= zWtEjh_);7F>4f7l^-w?cvDq0>YiC`-TZ6ve)9w?%-3WlOU>Z`ooKR>`^4^y~J6<@x(z^ z+w=+JFtD%PbZrT$%D5G#V0U=GOklRj6U+E&k(?&dIiqL~(QLJCGvz5;DX`I`Oa79~ z2ucZh7xUTo8(PvJqiDEY1j6+HF?QBrQFd$FR|FJML0XZJ5D*YS>F$yekS-CB?i?5d zM5K}K4v~`XmTr)ap@$y228M6(?7g48pZ9zBdpyT6e~jP^_r2~F*E+B3{H@IAF|o-% z5OPTgL=DnE$KmNDeQ~ckoSC2M37?(wjWim5sHV_H_=#gRD8_U0Q=iX_df2VTnPfA> z@i30gD34R#{!ftxcVZa5r1J2_8pXeVs(mc#K!DW29cZxyJ61ckXn40>b_csgSu zUJ@PGj^gZ=xT~E4<^Pg(aynn5>)>(W)lEn?{?E4>(f!GnswK}xvZb{j5W!<~pmEn4 z_F4W&E6%bhsdNOlC#o*98qe&yR`=jBm%@#w=+0-FiIlQh8p_!aU$;1DqAhz4wF*S2)!M(Gq?Nx`65&IY?dy#;ybQ7mo4R;c`;#puAoIJcp;p=<9W_KMrY}J_s0RDD$Br7%aD(ttn4( z+sFk6uQ2L?8p<=Hxs&%Z$bh;zsjqS;&qZRi>ZEW7k33?mcztaeWoTHiu?f+gl;K2I z(D3QY`Sp+EI?hMqa)I*RzIFRPSpNK`Eqt@?U4Nv-{v2uhz@=qR z_h-cBRS??*r+TpcFW{4F%$)QdnJf>wlHzuI z+tA>EN~Mjd{b&8Q`0iWMKLpB2s6ST;6})D?d-p|^Xq?TxK!W9M%1IMnB6f7nxwQT< zr{72SsWO@7MqFiwX3E!?n4+cBpe>)V9{#|*&%x9lfG0~|GOh~|XZAJ!&g~149hbmYjrYD-}nd5irgux$&jLpSi1j_LbSYcoS^BF;hk; ztxkYjSUJ2%epiIzya9W>?z=biw3o0EC;X!Jxy|g8l(sa>kU!_W>jh9~9mp>%9;=7{ zDEYkpos91%?N>OEBURY=b+*nHa3L{m!b%5m#!hX8FIuo!f&%oMOabXju0M%){KdAT zbYuz%H_)LnIIOGoFi8ak25NLx-f{IbY!=p!X|O`SsTT|$oF8pU8YM$Fq_M3$RvM1K zkfI)AH7cdOmk_wv6|Dv3RaCZb)7v_~6-|Reu2n5Fkm<|zfQW`65%NjA$dQ}3&b1n$ zp<<3v-_6s+(a3NFI%^m1AF=IyH+MKvRa?OyGxFjFanr}D+U>EajzDFOABi+}U9|P- z$mNTJfmeGtV`W~K!8lnfk0WAV=sf5DNQx`{; z+o5#lPe^u%3NlMRh6FZ)@!Lb!(jB1YSb3ZZk=7!hUz?2Sh&@HaDjspd5bjiQb^Yic z6UuVqoBH|jv^9iy?fFQZt9_nk`45&x25Y?cw{gg~D&y~L(*#TlyNr7K=vNo*t(CrZ zNmSJ7lRk00LR~7qIKJaS04EVM8ja(&&xSL6h#WsRPI0< z4;hr7O?zWtCmum=O^;|ixvmRh`Pehu0I4i|S82tsRq7P%fe?GEaI{wX9uowdXPO8EUuS0T7Vo zY`CxCzIl5)_&&2{Ss5rq+h_4V3QTIVu-R)Ik>{NRQuz}N?Joi^YPakX_*_dUB33hE zpk-HW{w`k1^a))ZpqO~7$`)}JQ>f~5et)02X7K$N%2dJ}iyH2pfU^oM>r!wAU%!3B zen8KqNBBggi>~wR(R%!p**?uoC^$5WwO5`T~c0rgnU^< zug-``F!kRknTVb!;P^0V4V4kmc_OqXREOLtww$q7m{so^^QL;LLh(FX5Ly?49s^Ibdm z=@Z?iOi`McDa_=Nm6gk`m~u+K^-FWxGplG3SzyUcZ{X zvlzyhtGU2#i(mY>8&+M0+D)MymCLc=M+KLuwV+&&InU8L({1$wYyLpGm@uEN0F-~p zgA5o0hfKZ>`^4&HNZhZS|JdrC<)XEBo;wvB6WXDwMrHBy^JukL_lJ|h{YBx$taegj zR(9QB1I|iH38JQ_G{+1fnqmYZxN9`HvLwNQztY|;7XPd!icaCm{&g^@$H%Xl@RVPd zkVH6&q`9?>D3rN{eGX>edq{#du{3qH-p}Z1gMA;iE{5yq|;01 z_0Q>8dQNAn1Jf|LNVB5y2}^c)W5L3z7x)}Vl^;f4k$A6yy$^FLuAjq+g@MOsC;ZSo zw>_8l)edlf?L{L_N2?mnmLp=sDO%*}c|3%L8tlqFg6uTJaEH)t9=p#?L&PabFdy9mc9<`36|Ps&7&$7GUN__xiD z_tnEu=9d2QzSVmQ79z;??tMLE$1|iCZ?U@p{BfwZQV*MQx=6a#bjwD^0Z7^{eMEk8 zo+Ddg_NE=~bt;Ui|FoQM(u#Aq=hn4|XGX-GSB>yIox7Yz(Fv+)Jc`Lm6~uQaXtaOf zk;jYe=C9I>;kw8dpv+NhRbr2YubKK3fvHLVkXRr*3N|&e{H~g5Tex8JDd$m7H1mOX z_~-g?8~Z{hqsa#MGdq^vjpR23H7ePeJ~J7cSteXBc8SMAld)Y1!{BIG?)zd&zf)@# z>CCNkkUzg>e?O|swzHEZpIO_~4X^y-ApD}EHF*z@kCT)42uOc0zZyZBOkyGjy|r^Q ziyBUujWemSA_0Zbm+3#pkB6=WEt|F)VSZjqC$4)qmaG|Hr4}6ez0| zx_c=&ssAdM|3|&`|9ERL3J4388$CVC|Kk^b2Dg6(y?^|N)O?@^W1z5mEZ>mT6L>p@#J$G0p{adl_@BmWiKph)7CuT6ZH zQB2_9O4nZ!0{{QjXUX0e$rxUd`)hIBfB%pd)kDzkc+c+sA9wMWPs_xB9K`y5Hs`;? zguk}cUnCgN1mD1}ffx(l_y51v|9FJ|@fO^HaHE6k2g>ebY(|4k?Yr6LW0O^COMJ^j0Py#7DB@?YBTe`yAKJfL1s82~-~fBEIVwW~jG zD%AmtaxLbCwcB5}XaD`f1peTeeS4{N=ifW)|M8UmdWirkfqN($!&(1#J4JvPcxFqr!*0?&-*4Z**sEf4!5)7hd~W)3fbI$DQA= zo)t{wJ7H|rNfJUnl=TcaikHkVE_}b>h80#!%8nCs!rDfy-{qx4RHdc_{QvLo{qw54 zn8hiVFfP9-LyI+J)wl()Wa@bbY+105OJfR;&otzR27$|RQQ0P`ytwB+@!D7PMuA~>8Shel)-U%kpEt)9o> z`$?HivoG-!$FxPnnUC@3|91a>>6IK_*LJea#PmiEI`uVco9ZI&A}#A`3XL_{-jmf+ z*N*%(?OZEiA%}*ip0ZkN@TzM5ldaMUr&&#N#YQi(+1!z5+WiHU8|mTz(%(UGfX}zo z`|9Cg<(zC^@89T#UPtI`x`P8TlgJ#>B}ra% z45xK0Pc}L)E^Y2{L1$99e?wq?=d9C5j5W3jQ* zyGcCG75EA~L)hm$o|Y3YYZtp237K)<<*OTv*u+dfF|3||;}^>-ET^Y7M)S5WPdX++o&NTxTR3H71zPaDGXU9` z24#*0dIL%3J<%)&*d*~Bma9Fg`LT0LA`M^O(}6uvo?Hq?A27AA!$&QM$LFjH3ZzG} zi{GAQfI6EbkJIMc6)t=4Q;N+GR>#12xUQu(Noaii_o!krq1OYkI>dJ*?Py0ge92HU zC7GwuzV?UiPl~JU5i?4b(~V8Wnn-CFPKlF+Lzp~TKrBZ|M7R}$i^ZC zicQ!4$qKtHKE~JrjoN2;hrsV{t{`|6$$zK_%e4G~5b!`5_ste_8Gya;F95s<6+aYeiR14B~=gjOmqU_d?n(8+fK%Jz>hicUs=vi^ zwRfPt4XP6Mx5lv-v)Fa>O%6*Eo#P!DrBRR_e9!6z3$}NC?Zf30(SN3mPO9SXnm@n%PylY@G&1;+4ZqI&AGyPi7zG_f*F&d z&VxDU<_nHt5bJ!o%p;di`fGdyjQs@3S=QdjC;cypb(C z_#VxFgQe~?yxbZ#r&FulI4I=!rT*NEW;Mkbb>;*-8Cqxiq*lUx@ckYZfJ1}~@E>1z zqLzs4*Wz;??DN=kkX0hl_8;s5OP7XYhho}zR?JkA^NfKH=KaHTRBlePF}vCCU03kW z{f?bk$OQk%+~(4PTp+ecby)j%B(kd_j?-ly4E1a#m%X+_zfg+-9bj8FF49rro%n-NsrqVi@br zRud|EH8ygv$#}`%0}hn|&{ej;@@-f-V`r{n**W-BiI04!#jAE_BT1oG4OI&0G_Q-D(`}l<(08~6GiEP~3@9}uV%oWS# zS`wNAAqB@4GHb?GQZDT?7JmKZKKf9B+2xM#3}IO+Rn@9B=$8tCjiv^lDugKi49Whl zZOBCU_3Dj7bY5~8P1}&ab;*kORf-MwKeKPpF?7r;>(5(~0f4JP2`NYT(T_6bQS+A{ zcJ*N?zdls=g!+N%fEPR-mq!nQBYqiFuuDZ-fLW*%OkkS_4WMZ3_N!DNa>x)gVruT$eNcd|BR@oe6h^ShdP}uL1}eB}@T^Yk51r$b7lv0)oHo!8 zQDLng_VpX+v(HGb>qU*Z)Ou_uqzE26omFd8yGqin^~ihH%CHx>mbZqh&ECs}d0y4S z7;tzIcUOtKrq7rA%B$=aVKF)U>k+<`c62>?T9sCjb->?d z4r)Cdbk)UxV|B*11Fa2s)N!-eO^0a$=p+C=&4S&0bf4%Dd)4}Tg!+rb0gxh;EI-vx zsXw{fB^??_%n~wORKMd^yEUwfx{xuMWFdd=0RkC}IwG;CuYc>|(u-e*$)V>KS$!Hc z?N7TLi}ELiEMlez^CR$)6pxNz>TdLvPp{@{>X{&>7zxNm9PR3(=<}VbgNnYbuo^Y> z>ijzXEss@WC@HJE%kNgCeD64;>LBz`IY%C>!x0eN2>>s9t6H8o^CU&Bt9o96$Z0~L zT=p#S32QI*3zk|UO(wD^rYz{pjb`xDcB8#jx?Z(uvSc-n`$RSF2 zRJG_38R*L8mQ9~xZi_K@*&t_yj zEO04!ZKwiO5-reV&q&8RQLaX+rJWtXktM)26||8V@ViJ2_8|#YZq8YYOoqHAl#QP& z)Zr!NvI&y|4ou8@Yu2rLkUnc{8xSo`HvYJn=6T|vIP6CAw{}GI_y5=sr8x6c&CSa0 zL$}sOq8bI#-@kB}%lJWjAb9EY$)hgQa}K&)*lRT!QgX{&Z&^#J+N-p1&(W{HVe&ZF z@yE6fQiayKf^xxS=-gul0le0L3J2+KaMQ8#2dFM}h-=f0+Wu-k7zov|Ba?uQ>s{$8 zW*Q%XIxx0->>4Ct&0fc;EdGN(4KltzawU^mand6?0nnC1 zqrk-tJ)>;-%U*%23w!Vr?cb8NRCvcnJWD~ZwyvGos(P+QxZY4(%C|&+V{1-ti`I6K zqq{guT+qyvvt-@~A@i`fbj|EVe#KLz?7=!$-HOPP@70@uZC+LP`_{d_dL&r4z#DlX zxYWVwZRuN1iYpKFahqfi z$wI+cl+DKg==ll4n(~wA zuq%{WWJ3q}cDlLob`59wPbU7Y zsf}J0%}8W0h6F)#*7;U25de2WW%26ou4uxYRNcEJ19jQ9F;WmKjH^)zsM)m(*TSuN z7V8;{UC*->Vp6_SLKqY-{0MkYpa3rp>fy7|ulAGrYS0e&~+c6Hp>)C6* z#Qg^MO%BU9kTyDOJ7v$wtQbvqobyMoj3+cqk{%HXUU_4upJq#Z;P>2Qt~@vXeG+Gq zXl2WCGu{VO{n98_Eqoy@a68%%NZu)s3|(Tj&`EXev4qYTw!Wq71@*VvPD8%L;(byx zh`IWNU^3pZUvGpRKdf9W+;&aAe{9icqLTbK10!L|C7m4zJzL#C6b3ZhP^C#+yCMI; zC@v)-!g)vBQ*U7V{#DNtBy>d^i5lmYK2X(jJSl+0TbBdkUx3CW1!T+CmxEdDgf7u0 zogZ}3YuZ|4kvqt89*mlg{)oD76MgKqJyloDtXoEJr`8yO---Zb7f^1_fj_{M6E8Yq+chjZ%${K* zaYI1zfESQmT1}^xuEPlD8dqKSJ#pyHxSnUyIxWXFbIRqTt>_)i@x9S}4JXqgS@*Y8 zyv&(g>&p?Mwtvlc|9b)at5{ZX$1A9E@H$egtc&q&VA{nGb^X0R?3}yaUGvgFIN1@p zQ^SXSd1@OExIPmsJ(n(STzb2(byvCQUF2r}{RZz}i??w2eo7TkjF+3M>;w;GWVn1i zgdDPNPL(GJMhTG}Ckw94`&f2{rHz#s^(dA#?QP^0RRFJQf2auv$G^n_&FAV#6(!1c_-lj_rS zG>{!WtH|?CC19ID(raL2qT$%qZ5GZcB@^9rKnzh&p;7kle5DR4i#f;n2>>8sEB=3L z#RP#uNn)ODPNazw$+Bs2KpVyy4-g263?!PRe)@ zEW>GH!LQc$KKF4Sr`~h`p&;Oc^v%4xF-==g%Z*ol--`%;jVSWOYr9gR@xHK9dn$K# z)YY{~oZbBQ&&TZM@pWXGcY9{My}9jICqj6)^vgGYGkjys+z52|TY7BU(=gb*8ZLI( z;{2Jl9PGUd{iGDSwOY-Rje&pyja|5zrH5w8h5DYurLjyh`UMB55mIXH>hE_7yb*7y zGAmc0Qf{USjLS#a91%qg`G^&(#_z(@cOwtS(8RYB?EaP{G7M;aG01hy6sDrN2bPJl z9(0SmmFK86z<_hP;PXJW^esCHPP$0{T|JkETJagvVZ?ntRZS1NH3V$lVOm`Y)g)n} zeo6LfWET2^JL18=qhUoJ^fH|RfVZ%?w$49S9fo{+p8L>LHZ4>THKAGd(SUu{N#vjO zb0O)6gBlOQprY8Y zgP`-dUW4~&uFmwv?*j8{O0Z?+Y=saoiR&8N!o2r&7^FY}ru6sMe$HoXv;My+JTAT! zP5l_Pa+>$Loo%^#X}h%5qoGGcuUu_Mm!BGQve_;tyJ>BF4jiw7w}UXg?`#>W zmz@+Mww@}3IQUN^83(d(nEquy=7?(gX;7pIYrNt&lX#Cf#iGa}Ofv4j;L}U`ZpW1F zREX-)+XBeSG5`k<=kAHQiY(dz2mAJ~F8u~iDPS^_~-1T~& zPu>BP;#0hh(#9o~ld^UTXjo_b?jcD@NpVS+J99=R$!u>ccOt-EE9!f|vrfan-!OY> zSt6E@SH1!$EAK4jQ_g;AA5%Qao7b;9FT5stmC-A2H=73|?ll`eqR^~ySPyqXNy(6@ zx>u30ZnOfztI_Vf@P1Tlb!XoD{pGF|fVn*4q0wEsIpAH~8Pro@IF!VdhlgjvT)M#Z zba&ndr~8(s;uNQjbLR$j#0{)4@Dh50TLrzW=}mmNI%yo=5x5-B zZr*E^U-{8w{?pCjJhcJ!%7+mFkdvMAZg=(JcLnd5pN*z7ms-PgO~)&O-z0D_PnBS$ z361_3&1a)>-kEt@@*$TC;pByek@>Os>q;u_aF_@hjSw1*&B2{{>%B$sz)Vr3(^SGG zzzT38mN^&R1V3i4Ffj#CLAl%1wx_!WUd{9P&xhXx60wMxg?lbhJvG4m<4SK}q5BGH zg9BuvR-_wcHLDx?E)Icl z&oCDYUm*OM+~Xb}oXBWhx?+2IsyuJMgTk{DNAO~PsUB82poNwp_IXLRGn`hINTc4kKz}fd zMXw>DBvD98>Z_*i0;89tNXQdz8l&z=tVd6g@@UaQ*n~Wd62U)dncl2c!d?tDI#2l7 z4ry5*vHER|Z7-PPyc9;`l$x*pa^LZH)TWu-89tpt=Ypu85%PGu#B`*nVr6|Krz^WJ z;X`{+oL#L8K|Q#r`Kg5)VXTG{kb-8Zd5`&sP{A=d?%Kw9}{(I9KIoCqkkKI1$%lOrys6w z4(6=84IqoZY*X%J^c!-!bT9F9gugP87hcoCFGP*&QS+f2jwCno00Y)fzf``SaN4}t#&76Bcx*U* z@5enQf8S&QWsG6_pJuZ2U7e+W@FF77WHfZs#jv`r2I#`68mCnHH0N7$>HnV!OoP5)(`A@$)D~wRhylXO>73o2`jr zQ7CGiuG(hLn=%o4womx0zV4gabj7z_bb|2B20gkCC{hlkyxFqSm7tb{opQmU-I(ih ztiNU><$7^d5F}`~+?&?ZjJ&d1NwWC0S<}Z_%06zh+jNsVRX{qNW(eM&*RPi;^-#Ij z1luX6Wjv%miZSNHK(dZ}-sOE#j?OV=Et)03f%`c0{_T&*t1Jw(YTc9wKLl6Ym(Mgq zC!6v6A#IoHjVKc%f`dwqRF~y%k{6FVQZE3m5`7#sy$4%{*<3QoM$xKh{vV+dxLzL%_IJE8-^7W? z#6X2|>ig4hs!*Z{>fI(+s9Sc&TY~4-j>&wkE7zE_<9l|5#Bl3N9p~As9-S&1VN%^i z#1m*wGxo!xJXOKh>dUw5s30o(WxTW# za-EO2G}uF6>Fs;G%M?fbSQ#+nC>INuCy#j)E8fJhC7;Ze+4EYS^U zUQO$T9Hn@oa^a3aN@WZHJit?}+;=G~6Z2yG6||kN&*`YvUfW|F#dnzleYShq;vROu zOVnG8`K0(IkT=wY^MO>Ij2ad<3FY*u&&{;dqpw6o46@$Oc+8Y zvkK&buACJ2^y=PNR{pWO9yC zw0WDmn8$!fpRC|;!~V(Ba=!;;&s6hNUun2aw-lpxG6w|4H*E@ZN+l?K>>glZk=!VA zTNl?tOlS3EnvOiHpy1k_t3}B81`rzc#uoDgh%B`S=fksdzaqJ%4WX$MtR0$x=;tQez@Pmfw&U5(gu5f(-aDb5H0SyLHF-mjvm)pJ$F{_ z;TyNQ5dvl!x9C6CWxmbo9?r4WGs^$g2H*Yqkov<)Hz5y>M-S)?hg)aa3XirZ3G9n> z>$l6PSOz!6$yjV(>6E(#*JbWd@aZRc?`{J4=#Y=8i2#*a5DBUQUP4T-mL)^@X#ZG| zB5N9ui#|*Yrqw*E*A`2tNH*tn-r4_A2C`a=ZhQBtF>alH%Mcj61vx2>du1Yp(5;`D zbfd@z;`LJNNGatjeyn-tBgT%CrI_Hx^EYUz!yuqr@r5T$BgShH^*My+{U#0e@E21r zGdyZ5zV-XS@R@wjd`K!2xokz;4qZeQ=xag^>v$>>v-D&S9k`W{qwgF5+Jf)Uylg>Tm>9d!} z^V$8C{oYpt>KU!dW>k;wdYqi3J0@^cFatQg7-Q4pSgU5(=2OwRu`ff8s%V(ydItralTi;=omoD`mjitnTe=A!&0XU-eHhZd+C$R>`19k?vwNyv^eFWfp2~k9p@p!;S|vI=#FFN<9{jvBv6ROj$^#!}MRb zaQrhi1)&BdD_$%+B)WbpNA;`wy>@cXx-We`QSiBX$Tl?9pNzL9UrY%{_g8$^-APfU2_>nlv zZXVAiN|&;FB?(E&>W-((zqM2v^f`LUF#m2%J@8S=2sx;=oHReFK;MIkX4&&}_lQY&p@I$yWaRjO3=5HdGB}FSiG{~!YB9~oaRhBJF=;UGR_`w0jlcJ0=PFS6ke`=c&WFT)!R`G=6D846`GbR0?>tv>nkXr z>U46ErMFkfXS^Y+Dyy}jupMO7bG7|yF_QHM6asw1E|WQmH+TU_{y48!@|6qBQ|^&4 z^;BzLWL5l0%{TK@kt>O{;urs1rNe~MX>Y91N47|itIjQirHcpNja-swI6F6wxc9LZ zlzW)p3=F^#P=A(s&dRWLXy<`CBR=G*V9h1gc~tko(8i3wj6M|CNCL=+A4D|`!nhZf z6h0)}HK|yL2^M%a3GiS(C7SS(J3%=9ZPI?VJCLRR!-I9m z-cBuI!owLYIpV9#CrI)8mFMhS2dZ42`|ETSGO6R{jO~;+sl$kMKRylo&EBM0>vkk* z$$V%VwZv=kpeev@;-@n@(YaQoWlXM~M;8A<-(FWl;~>$wF{~b=QmLEw2GKFUDh*oB zp%QtuONgFZZWNPtnff#N^EWmE)c69A5eGq37QFo?=sh;`8bYuApbN?MT*rGI_~^;i zkxf|hoJ5%N646W=7U52{HcG!vic!i6;`{TG!uUgIbJT$`?u@TY`iPha-=m*gUZD{7 zrFqnuO}x_=g=si05(`H6Lf6u}M?24r}nZK#eUy0u`=q-co_7eW&NrGky2{w(tjx&lp+P zQpUBKAwp-9aX>(!5IdhSXfd3b+ndZU*~sGTN&SB75xzX9A=A!i=tK}h{gg2IDox_k z)`yonr2|(A(M9SEBPP9(&*Tz*D9(3TI=ZYT*kZD6j(NOoi09A=W$y?fMZ9A9#JZ5o z53$g3rV87P74%Fl2ssfB%3+mn<~qzP%3ge^XMCH66*oE zi(fmELO{NmH@6Gu)|?wrrHPGYjn2~(+N7&LLDt^t|zF4F}|KaGC+hr;v^ooSbL{!qRBQ`cu`i`Y3h(V+1L|C^@BkGB!u@kt(f2XRFZwM{k_RMSetnfz^V8T7oZWW# zizj5s*8?b#Kqis~!5y{{TFaUQExXxRna_>k)#yvFQ=Yg;IdVjMRiw5 z-+No!uA}08RGYY8c9+>??4*UqJeZWT*pF4wLE^=C)!K^tw^QC0jQjp<+sVSTFj7O4 zL3NxJAOz=$?N58k!XVo8IJ0jaCsN@u0pxYIoyO#YMCflXM?kieE^Q`@Q!eB=JPcgYW+Cy=HoJZ}yvz<1GdqJr7mHlAud*>=6nx@1?E8%Sm9+ z`*lJzeq8-N2>zH&VHO8|WAyhDhZ~wYCR#gDnDuB0wg>V!V!5mJ*)Xo|&^p80MwBv? z)WPordUd%ld=aW#V$kZQW6~YTFq|eTnWS6lR_=avsX6_Q!cjg0w@pk;tK7i{YxH); z0}}grq)2uBoq5it{Nk@iAA*0a)*=#{n7>1dz!@M9XP?Yb{}k8;=_9N7aV@WEs2j%)Te@Xv6UN%XvE}e9rZRKUXy`x*()c4dhe8iC8{g_KTRlw4UQM z)9^B}d}M<5MX$US=J*r6Pl&Mi#*lXq}=j z1ojAUT!raL+MsL#N7C_&$~Yw&t9JF7%|ovcFsg;-fRAl!2K|_|!bi!6HTf4W;p$!e z&v(4gY<_)R;0eB(NjrU*OeTxYuUQ}O;e0N|AP#ed>u7bv-C5>wLQGlay?eK0^s2DK zB{Np@@xJ8|D_%bLqh6n22>p~`ZztX zKWrXZkxrYpvJv*XJ|?-~O~TekhprE2(Pv0t44-^fCpvij2+{RD=BL9k#TSMJ$(tNOyy@JaQzpAmI)@SVQk-DXdN%42C;AX zU(hVt&Gig07)HwBT#^{PfBH}P7!2;Ol%H;rirA9osueXzZxp=R5+H!DVXtD4z~dq0Qd$zBY-MQzS0b%NQ8#45uR>boilwR3KM`jd*frffgED zV#euH$6rg08PD}p#DF>|>Fo0}xgX=@97(pCtqFVYE7U9Z8&D!+Ghqdg*)k_HIV&a;eaz$j0FquFYOceb*`CLuTs>_x!C08oyZ2uD zI7RqbzGBB(iUh|ja64N*=9@k0$?L?BXPpc5(k?26z8MaV5}9RC{LP!e^2C|mPw_$Y zqC{LM7QKz6%DvB?PTjf6DA82Gi`~}#^zKio;R6lRc$Z$c-KpvIgQf2fbV&^PU4oEk z5tY7g~fx-Z7e}^wR3_+d2ec)mSP9#jn@YF zO2wBuCIjTG2EL66>OWfbKE5SU;m$y7hP37Oa#Hr8mrgocUE{>fK~!iuQc<9~n&4zm z_NB|1`sFTmv<0l8kHZ(CEoY>?5)B~2QZmmG6x5KD&yU{3d6c#-@8Lf%ys;c(_q$b~ zu{2faACtROC%TnG@_PVD7l=U^xocNi>7=kJZO;T1SB;XWHgL1lWDt5)7OTpyfq6{J4 z42t*Mcka;60yVtZVy?p1rrC13;-I);)>FTcKLmZOJy<4$oOi>u>is>@5`z*LgL9r& zm2%>Ow;XEL*`(}*Sm|~;KFQ7BO8BI!kA&3U=htJld4P17gG(&|!`q2J2FbX(Ukh$K zt|Ev2r#m>dZ-{=0CHlyFD%}H+$UIRh(!7sw`%ON-z1L2w)f&xIWO!>wJkvohwmF^) zxh`FXye2S_uXfswKaMBiw#!ubC}r{}vp$G1EYt{d1`hm_$}<)(v6cw(BktHTme}ZJ zgi}jWwKz(uhICNjOGP{jK6Z)YVD9~C=D$D88F3ezi0LO`vgK}~TrIx%T?pg3JtK}q z&J#7=iCBFb`N0L`p^XL%Mr1;kxlq4-_|k>~4sD_SB&~E|Ov>6=3wmg4>U~eTpoPaR z4NJES+22IRnLLJz9+Kwp0fuD%EJ@Zwyd#NB#b%M@(Szka!-Ls?8xTq&|Jet(nr@T3 zHz7)d+5(75H!pS$49lVgJ#P-2%cHJ*uYv=`)iiwnnNL~7@FGph;j*K7zZGm7ZvVvi z1uo{sSEl9Hi<})Z(+R9Z&MElFojtPs#PLOP<;AL)En5<hK|{TahKp{-)(bw%x~c{ zi%(?rY=UQJjjSDDo3k7hWLk547^u5G4DSnIkJ{@c^xD)6>K>PqNxDO6vfcHm!xSOHGk^%{^3oWX7`zM z=CjzJ3x7YTRB`!8uXc%5xBK)C>3s|VOl(EXHs2;6!Zg#T>L-)c>Z+vt^;PUX5Ofl|rpHY2`c1m1}jvvi~@D$Hy)Dj^9 zV>i&X-{|~S0LQv;BrmE6UD>Zv46qsd-+(uNc&_O!h_&o?S-ud37!6$xVaG~x#AQtd zN$q#v3_}d|89Y%JB~E>hBUYR@gWC1)(#pm6(i{=B6UpywP=}=OICg6=O&x-ot90g8 zG!)i6xG54VAJk zFP+3y{W=yoy#Nz{D$9&fYPWKCmI&3Vd3Z``cQ@KgxZ3c= z633gD7|(Ya{k+DUQOveu?7F7?b^4h}689brBXN9FICOs1j_Pe7ykkHLp@PN_sUEQW zu-$3LaE9(5F|gNXiFpY)gM1>F70cvyk{J$qm`x+(*Qol;EN#(Vd?RaCZK3^D6Y7=| z=d%Nx{xztx$*y%~s1bIe9qOVn*}q@2U!z1C{}=T)j?^9pg0jxk1touO!Ea#A zWTWf%1>aOk-QNzkUSTM&sEKK!CMBQal+Bh;daqzau*X47gmsVHaLO~k+8llSGURRt zMbr$$+G(J5&k~Q^M6A>NPg}R_uP9e}XOR zhW~?1=DfeCj_H7y>Ck)#X#d9Kx1MDD7PMW=w46?|k>Ku(W8@klN2}L$PVp|jK8PZ( z*AK68GfyWg{qCMgbg0W#v19?<{AE9}4k?Hrj~Uq9e@TrJUrBK1DxVdS!j@upn~p$+jcW)`ZkqUwT6#A z^SK_>;Mk}9b7I58@Y3&9)@LB2R$`C{CF3^>m>rw$jiV;0-N}O0y_k8FwAndCtt;-3 z9Kk%tkYRVRJN>oeW>9ED9H-v9B3)*eB8L~EC)c8QGa7~?`ghQGTpSj%ja}=f+mEN% zK76$a#S)`HYTu3GQPs^fD+`_ApNlidSKy2qrO@BM8JJQ!mz2h&ec0_>&~*JI zn_sY)@!O{&{WlAyPid0&A2WkUxJtk>-KtS3qkXu@nxgN9!HGgjz#YGxflu8xrprtt zq|Yq?7+Z0++ER9x%*Oi$7!NP@uA_pJCRE+bV1$vTt%%vaS_41PFrDA;#4dL))MI0ENBzg6eGfs(CS6?oG};jU#t2Pub`WU@KSNuIn`g6S@iZXE%C_U6_4- zF2vjyMp%oO;>s$CRBtOJwlmS&GX$&<&Gcv%YL-uNAYof|8E!{} zCU!;TVPTL<_a%K0xeay1Gi7iAP2jC^*I6;-TSjW!qzAm8g<@ZI6v~_uE9A?xZp)mG zE+Fie$$r}0$asnVOxH15FvKNvYvYnXl&x)EGkk1NX!)&#G?IdTrxqgsK$OYmwDf~bJ%Nhy@QwEtdp?sggQpD zAzt@VBavq%_VdzETcU<+bFR$w<~V@|Ga+Q~)T+AS%7bi}A7_eXz<&AZ+r{oyewj=X>}psmPht$Ix9Z(3jSl^8W9fl?Q}aZ9-DsG0&zi ziP0QMT)r;Bcl-iB%}jZ(dmi}`wt&`#v~}jsY6BmjryDhi3j`&haM{hhmfaR{)pnfC zdl_;hqR!5%Tee=S{Q@nV1Q_C4#B*&Y?wTr_!818*D*PVFwjNF}YeC@P_yCon~1cwfV}2^WU_gm$;$~IW$Gr zygw-lQ1T|Ip3h>>+tbQ@JkCw2WK>qZWFgG(bkD>FJFVAOs*))sIZ{LvOD9dcSw)cz zn;!?$&+Y7Ywo^~d_epxj9yuIhucmL|ZvC6Y^c(o+N-Q>>4QLAEekvk5{h4({p`r#7 z*C%_hn)6&%1_n1~_ct>XVirIZaXRUUEU?L^H+UZ1U`vomWq+{CgOby633sC0BZm9M zfLMu1-(3j9;&C+VGx>6@u5QY8hp#RZX)NxBRugI-Qxcsa<<-R)6wT9QkGRpFY)Ev@ zg8G)*Lb!ukp0jmlG*4cFYBZ8ri=|SlC42t1Ydr6??i05DBpwBhIsaFy=RqR{XXzyD zs(Lz-h97~NVd63J;cTU?A!RQ0Dn+!mn;3D{orXp)e&jbT?lBnfO?grSv-bWn@#yN>=U_^ zYZs_nOJ9UMEP{S_#Jfk=>hhz}Z909b+?p1^R^KA@vEHAo(kFkCaG%=yO1kMSb;FE0 z!kvQGpKM{@vosLLyjnh2D)G9hft&c!nqsV>cVJ1qdd1r zT-5PCEJIenX@en(Ni(`d245jr#LHU02px%kcj(OtAeY1YP2z)ycCw!;-;*S>N9@ms zj=se_*yY>3q#|gm_t5@36r73^`?AD%-2zkfhvGgZ%Y|RXcODPKsZ;s>-0da@hj&uf zW3h~#;q`v3k>O8lfSGvkgu%sKEG zBN~pIfA|qqgBE(u7t%yPT3Toz3R+Ve4upSAnFdgHe5mTnSj_Gf_318tvS7d7kMf4z z{5qoADuN5W^aoc1nPeO9ou<)~+K^au8L-7)OlZwXrt zFdcPVw^ia;a?YJM_)bpOt3_t=3voRo=-zRxIR(yA12tTTfe#iZFz@Q>arzf+d9i?9i;=K;#H>Y`~y0oO6iqTtF{1}g3<7|qdsMops%UHa!ZeMVv8Ka0eL}eYGt6p9J zGh^u6b#Xj2McP|Nckj0K;$yy(qh@$ZuYw<+{itEqUQ&(&G0*FYp5%5oA&cX+ymt-R z7pW2ee=`_Rt-a;o7kNZD%E#v`hpjkJZZ*;D4Vx?9+@Iz(tycPkzT@$In-8u3+7^V2 zr+VQY$hYS`0o1i9Ql;DF;4Kts*IpAbQ*XE^N@1Aja*UlU_>`D_@M_S{O87Xcbu$dG>l@n_& zXHfns02&TUb5Im+c{8&_KIv_lMEX8?(Pzo-z90Ue5srXsA7k8`2FMU z)PYi?j!aH z(k=+L=eSV^V?!>UbB;Ei2RqgV+`G{;6!jw4mvdTXUj*Wi2e>bYpjqoCeZRAx`8i#f zEOw7J)uA*;@unVa?*g=P=M%4Q)AZ;L$M-uSU(^BTkW1=$8J_(U=x1LKm?14FR#ya) z&!*g~;%cqtvR1h+g=*Oj+WBc3c%R%r_-<*E-1)Hn4Ni^HL>bgwM)+f|%jqdbJZE2l zwqT#fd@V1;+Pw3l=Jh2~KfFq#IZo$kS7^QP7SH`hoaUWB*m7GwKH7y98D7ZB6RMBT z7)o+H`C^nRH1;Kx@ki;`M#TG0!3YWhv@Qvib7aCAd~XlCDD zA7^SRVGF5iXzgHHU}?7Uyn*L=XI7VlK%VeYZC2mm7j9qOg!Y;C+QXSekHfWlX&UG_ zMIOPYno(cf$F!mDJW(s~IVa236VEuIB32=4hvhzN0-vI(YmHQ|=)Taktq`;y`=hl! zJFiedIs_s51ah-E;;x#`)}Bl^fsPB ztj*{uIWT2ZpV?C4qMP@|ZI&*)&AFz6B&3x&VPW($erqy+Z>vFY$E@WH)q8yx;c(5{ z95Z)O>3;U(SkR#Lkbk4r+XX6ewZ%nzB(9X?-&nZpTXbK3m2h=3M1On(&5#EH5^3B6 zXptOp;X(ml7d&0;kegB{kZr2Wk};V1a#gQo@R}yy{bi?U`w&JY4`hW)-ccyfV977{ z>EEqGOT`Zs0h%?PB>Yt+-}U$bN|PzXmpgR!#e)@P^T)W8RmS6baR8P>mIo)p*d z2Gi~$H*rZr4|nP(l%(`ujMnly3uol3nZ&!8Sas)}JzIEmgRJR`4I=T?(vh~sRE zLlo1}WJaVBYLGF?;#oXD3-FP@40iD`4y6w!I zzWPDOsLA=fHnO!ifwZgDB;RMZbqv-sJnuR3z}EvXr$p<5b2}YF@caNAJ4w*S`wl0@ zLHHJ4G2S0_1{$AZg)5c^qeY}~0CDZqAn@ z7dnZV_F>osK6n6l&8x4PLddXYy}mxFt=Z8M z+%-iJWR@SGgiVE#zo?Vy$-j;wB&~F}5#FLOS#E6^qtukH2V{1y9{3Y|rB8m^b|cHVJKF{)!?GuxsGvo%&!A^tNh2~eR)++*bCLS$h&RvD9vqfj z6(+(ub6**F#P4;g!ebHB(mvOfRt3v%xIpS&Pa;N@pz^Qyy@GuOyA=;5pCI&J%TT5g zt=rzhqDNtK@DY!suR@YgELDT~F2{(=EMBnYZvC613cy6x4qS7gB5)=*ruBCPu*>Hl z-e@^?v}hr>y%#EurOPHe$e<&+9&IDsn=!@55r3u|SsTHqa zp9_ud>p-%vX|&_JNT0$Ts?1^Nr1v3FmD=e`YoOz8pIy{hcoSJSv%m+M&z6Fj#&~eV z*IL}A?&nOq&t|*#qj0<=e0BdAQ&k_ZL9#aRCfXZuU^66MaH4!!*6{IHHag7L87eh@ z@KIK&vbbm}m(hhBO(B*mk26^!?x1*gu$kR!B~F%V8U1n^H7) z%@#ME^lQogxE76%9qJbhmqKF1LIh#=mFq;8>;XCr)Sb9nLat$(-aw;^V1irU`8~h- z?L&XzVEGWft$ksF3ccd|>vd^fqGAUlErLA?H^s)Ni;C zW7ReD2rkD5*4`#ZvHz;Z|MyRysemgtPAj_;7o2{UK*GdG(6d`ZQSk`?cOJ0j&HK(- z0iv=#Y?#j{;(adjlC^tfEO0-kgYuW}_^%N6x1X|C&~G`2qD<2{hyTZYy8KFFbaF(n zJ61C_DqUb1hyVje@;yC3=qiG_thp}#$DKP@jLB$Izx(6AXdD0a zQ%sx&(Bs9c6gFsoXB++3JO1}qvCp((E^j1Vy4{+7z3$&1WBY(Rjs2aiIP~w|_v@?g zLclriwxZ#_KiRc^42=I8C%^wngo?tnPu#5kocjO6Ih2>@%&;zB{WZz`V?_M#EdV0} z9aUq6-XGd3^5-}9PtOs!Jf}vt@7n!e2F!mC%Kv;x77IOlKn2U?ofqAIzVJ7v$-cTg z=T&6_Nb!EXpMQ58b{*?+YV!3hqBGfle$EQkG%pT9c)1WuHFI7=u(J8Hv zKDb!87Yq6Ex!;sTF;N32Tcx0f(Q~g_;vZih%=iGYkL&V8^5%(%>4Mtb)QI?n4pEaY)8*Pojd#V1s6fnGY7-)v-HQ`#nsAQJm`$&S}s^4|I>;8 z=a1L!8aAD50Mdp5{ym^bd|kpK^ws!iJYDl1DY)ru`t|pzSesvn#BRTGMfJk1Rd-ZO#4ji~cUP`S+`K zXT-9fg{Gp+gr3Pw;bkG5Z;{UL5410S>vYZ<(MsMjyd7q$iwx4>(>*2OELR|`=K9*J z<6|_OsWem#XLi_Y#h!`L$WfDv)#YJ&&$&{?@dKYbqzkjVar&L=)O(XKKh{@m1r{&Qnb^RzNx!k{K?)u1Wc$$7UI)lk zCp?y;VWKL5WcNTfMzq!4rTCAWrt-=4iCXP2*EHxYTg2Ko>L^ue&pGusfCx=Y2SA zj~T9A{XXX(DpJyQZcyi;(11kHGQ#cSfWBF`?E?inXhIS!vObgn>#A{rVWwhQ`TpbE zL38K2Y#7xkwBI1wr80itg6?#26i&cj0C zdw#L@paD*f&b<8$UGoZL_p6EANAzpx$E2=n+6;!uq#cQZl|6=E9?vZ{n0DVx)CO#{ zYG7IJMGk^l0@3_oX#%PDH=|yy4xQY-0CiL=1kl^d1C7sZe$OZP)ckir;t>rnmyWOR zNlpJPk~&dgMSGkghLZC*RXp91pF#vQe6X6R)v2(B{T3}Qu!k82A&asXdSm)^6tk45 z#l=5nFJe%A3=6w{0$TShE+>1dEy8i`65Zl=+e;7806MD&iJD&?-(l3N`f{m$I+}@` zkN&5(&4wOTj`+t{62%BboOJvs{R_RDi{9+0iB*%5LyLJEHT-Jp3bmrzxeV;(FN>j{ zg{Xr4EXN9qdta@O3O_X!!D&%%(1#v!I&a+KcijOiMLV^_QV*HM!O;7fg737_UGt%V zWZ0kDfZ~&py}~NTh45;M{rvr}s>gu9nKm5HYda{v3u?n%pB_-l18ZQX7Z;#8 z^`tCnCMPbA$ZakyAYU~u*>Hw0DeZyQDIJ}}^j1l7W!7WL0c#*^>sBk!IUWjGOq%FWLgIBhF`?(O(@5nM)8X5bS~ikA0zqa#yNc-od~RgUy9;s zKaj}BvnZw(HE*{tQ+9b-^yfFtIFu(OxGIQ_an+U)4W%+)AF4$za+IL8G(Q=~ZJkT9PYD#W&udnyij5aR zLr7@e1mZjG8%tB~!`u92k9_z!Y^I;&^+05$h*qYn-+}%5duUkZ8qV4P zYWCGYwwx{-F1`#z+EUSM2(7Fo*VH5{0wl3Z8`Jhx+-B;GvCdx3VPsKOJ+{vYqLL>xZo%c%|PJ@?2eP6)_qRtY9f zj-)yh1!8M8IU|rlhI4Fn)`bI|e1q zWWd%UGEF9A#TanoOS(KwQfBk?p=-v+wg+pPyqk&|xf&Bp@bF|IHwPaznE$p+Hl(uA zl}0J9Y|H9DswO|@#h)BBT1(J8V%&E@ddbbsx~e&!yFGGSHjG%;F6!JfHrLGdauOY( z*JfIbEvjG+NgQr3#t`i4oxRBF;oqsOw-5|TiV>z~lO5gfT>-N|B$Z+XOoPtPY{!YN9nuj0AK&)pdSOR#`Lz*uC_=h<7Q-QkNzF|s z$Y$0YcUU?10R(r$M*{SsCA|ncrqjA({^DbIGZ_<`| zA3tI^A~b`^KKXP=_x+v}=aT$=L2qGp!H~qt?}thgRkKUl>-7||0!~3f7w6Z^#D9}ffo4QlqbuAShOz^(Qc`OhtD33 zxq<2X)ZBov;V7?+jluw*>fG7zn_R5)Lf@-9oUUg6W6(3T?-|sjd#)eIean~bq=_Dj z^(Cl=U;P{o3ank3N)2mjlmgC?V8PO*1*%syX}2E|fDWM?4Y(x3Kr{MH_guT+B~PM3 zn$QvCu_+Dk-Wi!PI**}Op_=IdPPDIJ0}a_C#lrL?XA*(<5kN3w8h=UQQR4c?(S0R_ z4|?iAa`hR(rV~NG2b?ftfzQH!)X;f_o!@Thv(`$>l}0MZk!o)q7Ey^1tcr1UU+t3vADu(zD?=wLF&`;H33^7EG+>Q z;Y2n=k!H&}y%P?0Bq&&5cZq=ko?h8>T=Zo3i{0@PX(Lc&@Q!bFxY88%P%S3 znK@~&<9|S^f162HMWO$w6E|drf8eX%tr$D&QWq7X?mF{=AoGL|3S{cp@^G(cka>nd z5KmnxWn{hCj|-@K*PN}e~5UU%7ciE_8|3nm4i2MJ*Z)sRF3B@VATdZx*IP=qwwEDfb~eCVTlH#$GJ4| z!Mf-@tnUP?K(j_kBx)7w_a!=%Im4sD+bhEPkN}Uhl$d#nd*zDg zq@3g<4KG&E!j9N;00zdWj-UVMugyXy#*^Gzq`@SUm6myVBrF=TA%GS(x?3}ID8U%%UNR9SaZYb!_~Bs7#1vVe%pDY`~-WRP4{ z{~ipi2xayL7DGj(8k0tTw(!c#vcGt3)ZWWv9*+=1)A}6vig9RsI!=}$Xae|I?W_EK zM$J5patrgjble-NSW0UUe&6)2hgY6=#hq5YIk|Q-Xc!Iw8K$*{l`E{6)QHKD%H+tjIfBovxX=S z(<$oZS5;1n(}fj<25-!1bSXy{_3kx0Q!a+>>J3^AiFy5ap8&Q4;E8hAVkn)^bw*+} z`T8Q*=1YJ?{IaQ@NnfNKr)eJxqgr}ZsscdR%Qj}9+FSB5$|YvqOQq?JcsxB_|8%fj z55;cv2oMq4KVyMe6H1qe4g|Rubd8yQp{Q6MIuG2w%MB^+vB-cN+^tah3vBpL!55l( z!na2_UTC;MUMko}wS4V*FFhkROIdSCPXF<(0|Vo2KRQvcxTuJP3G9DSqQCqL%{aQa z?+neu!e3I4&sBYJ?_4uqFH`g0WeC)W1s!T-+-g>kR2{?~P? zuA(a^3fzO7?*;<4{z7H~0^n32alhFa&sUT#7qOI?z;!2i0oa^_wDw7LVHFT8DC{kD zlMXDN11Fiic>>Xn8M5u@wh!^>8hjN2=KXQ^WJ0N;0Hewf%&l8fW>0>a1pUubey;Qy z2k|7$SnBt$?$as{g1-|7ki~;uiPTKYUxP?PiN0P&{XIHdPO+Dq98S<1-qei>H=z-D z9!Un5g&sPJ`wcF<6W2p zx4*1bDc%-xeav@h+i+RQqf^gRw09GzQ2Oi8D+~)8z`9tr0_?HB!x=QL=qa*P!l!7f zz#Vmm+*ARDm;pp|wS`+vfEv!$8!t+2hZxszEw|L}OcI8YXcLlW_k`j-8vRw*`0KC& z$8Rr@`a!}U_P;+8@TWJ8>F8e@USpCwagv~B64yjnULGzA1EN$*2^ADFXLikhZ{l=nwKs=nj%FSAQ7qR)~j>ZtgxA3S|2OY z_QDMZ@%OqV?}z#03hTAw{`JKl8Sg)W0FDuO>w&q}Mlv`B-q;PmvZnK&({uYx-6WlvI0YI z166a$%DMzM=6(~a!I(XmP$#A>7?)hVX;A-kxIo%CK@a2(8k`SZiSU%y1-yAv6 zYURgZHacEcuLi*EdHU8&sstuaso++X1YkU{-eA%QZiP)`R<{c}TagNhg4-Bzb|aaa zYHU5m#7&>77d4{UcXK6L=h&&2T<9%SAi=HnYQhH&T?J~}Qy0@JG; zbE|j}`cF5Qp2*5)3jn3#zHT7qUk;%;GeRJxHw#~K`}r0d1=NFNclr9*qYvlDEd+Z= zkL}L1P?5|VyFPj>LT93g1!A%X&#TON7)&m0R{})Bd41GmK+{BA!a(~YgC$|FGY#+MQ(jstFezrbpzcAaV& zW#TZMrFGk-&hA8kt|mWBCE~qHW;&qPnd}D|qX(@5;}vNE2!NtYfPKrQwUO@jP=>jJ#>?`Thqp+2^r7{+QPaG`;p6qjSu@wtH>Rr{HAO{6a87NPdP}W8wE_rO z9`N55`-iiXqGvMYqvS!3b2n7@@Kdiuvlrz$Up^_z>RdEFrQl0s-#HjMozU&tG(3fb zll#J^Yues;1d3#(iNYQgwSYRGP5P(?k1@ za_%IQ zj?i~v*i*UR6eek|ECPAfio;@eHznitK-UhiezDxXI6X*;B;zu-*oJ>9TW1+Am|Cwv zeC}ed-Hz*C-Q_|TO0gjf;I`IK>#=$B}W&#^Av<)axuJ#m*!m+O#K)3 z#_el+><#BZD#E2)dSvusu>^}AK?{tE75#?+q)B5q^WYgWZ*Ov!nCw2Eq1S^~*&CZS zonL(#OVE!L54dJw3vo@N)->2f!`zPn7~B>x8B4_P`eNj#7A&y_l2IA5hhA%C`Ks1r zerW1^VI`R%V>g44gVdfW1U|4ddHZA@1+7h<29OXH?7X>KeWYv4m=@4xpwuxX0UI3) zI@2-`CN{s|XO5tUq;`8hbT1Qne2U_hZKb12+H?ILs_%JVw+PDx6T!*mROJbe*_SB& zcVJqsc|_<)k+=fyO*-4zT7l-4+Zo(}KH_6zHC@1T0_=)!J)kC?LG+6M3`8|LB)aAJypMrre=C#r=UZI7vBsw8JdodVyqJzSko=YPc)+=B<#N2gh1 z*bE~19UG!Sf7LY!;1C(LoNQZ&haqx{M}GNW9cGy1RpC=0@M2D^U__e1)!)R$eRWDa zq}8?oVHR})nnfH|v(IRJ@@By{qWjly_&Ad@x4^#0)KG!XNw-Ou5nGvvEc#@m~`pwwMzaiXD!>g>gq@1Q*3lXH> z@JaSAxz0-Qyivf>YvMC76_NI6l8{6CxffpM*`eQKACX{T1*^3Ij|SqL&pM?`L+SRk zUeoIhz!*@+R3un(vdr2t84ievaxf7uA>pIJo30e5BDlO5z)@zu+Iq@)NR5ohsPpZ2 zz?}zHjb9M>!Q}iyOz`&53t15Py@0-P2X|-msN>(9j-OBU*MrK}V&lPEtPdZk{DL}F z5~DD%6gvx=fXvyqyf%#(PZfaM$|<8>|X7T;CCpRxQXa=y&aLgI)-u1!wo zH%%B~d3X|lB`9a=t8lvmejgU;sg7ni?(}UXnS@$Fm(?G`%fK~QK1RDGNt@w-fKnhm zZxdh@H(5Rv4Rg@g0W=%H7iOj@I~5{*7eBYo|2~-0A_BXs*3feGPpX9t1?uBh#!9cS zBFm&zslQ!qrk&2`nXPf6puU$`YT$>_KQV*AJe+!^NUZ#|rd0WKe>LM0on3GAK|36{ zc|(mF^(vEiq@hOAejh<|K1IeZ;iA;my?)-eJGn;!A+>vpT`~fZ>=5sGZTP#Vyw)Jd zG+F>5+5J_Qbq$syRfAceCl!cU3qQ66XfOw|!}2@Fid}RQKjIr-t>s8QBWQ{o(_b32 z%xhR*TfykLO!MSTN2a^uq~J(rW-y&Y38nrB$w$SW;u;Eu);+ebGR+ev$RR%aY|sJ7inPwTdUsW!Uq zd6_NuDnqnKj`j=pT~z5eUMj9mnlYd^+pdIX&N zkKtzrC2Vwup<&`hXDX3f_RogX%E%&4Roo2BqFG|CMIz5Y&|Y!2<*)i_scRF8Ukgnb z6A{lmi-3g$1keQ1mxKeTeWjkZxiO{5Psv$qiVpv)r`V18Y&)PN%>ZBmKzBJ$F2yAC z>uTW@01Humz-<3+d>X65BY{eL>-=;Oe7?ddm5(LF- zWDXu2{5ZRrvxo^+Zgd5t=cSMU4uzM?~Ad=Hu!XpEEtLkm`@^VX{}l5p_B;g{aS=8-_d z^+PO79b{`^Aa7XLf(UvGNf&@xxIqk@llzmPd5Ad$NTLT%9(NQyEoV|AyM-EzG}1`- zG+F409bO8h5bYbLF*?~>Eb%&X*6oXR-D$!+V7tpMxu^;OCZ)Osz}taW*y4v|yz~9G zy!yxgy_^1ox#qNpFSk_~O43g~&s+uF>zxyck(y0aY@s)>HAFOK=SYV9sr$-gJ z@H*tAr2|;`)%CCcXqZ|rn(%V@ED;#OyPiR++qKk7ILOvWF}BkT?_C7OS`~}(QEaRk z3Zf}TqDWU?&(lu&Xo_Rdghl$C@zk1D@h_`%jY>3O`}Y(4vi{gNd?e*k#J>iq0aU)A z@c{FRWn9CK__bKzpQ7bDT6o}pxS;~kc26Eyy3D1yUrvu3a;YxCTwq?DPF*AjpOVAz z!8Bff(dMY5^)c9+yD}1t>Y0&9rXr>I(Hgy@tr>LcGDpCf(j|R!WmmtDVUeX4x+@0? zm;h+%mMIRlbUhB2**8U3!xn(d% z39HxF)o=Gownv&%aKBac_(0A(gh9b@uIFcNosNAgF=Ynyx|-;~&ujt|E4d@S*~b`6 zbq74a^j6-`5x_m0j?=kL6tO#luIgXSr)p2&mr2*cT$5jkQIjVEC7GB$Wc|>{NUh+h z({J*%gD(*Pkyr&*bDkirEQIY;FTYAI&BnT=OzV60jT2q@k{Y+?2{)@jfEyyS({vE~ z<>DBL1hlKkjz*o(-wpWxxZA(2kKos;SoD=t2$uz1@8{ZDc@-tU2p=2!15z{BJ^8IpJ5`W+sWLxF?2~I=tsSb*`|?z%8X;+-w`rZ$MRF{~bg=Jn zq2qLe+(aS#?z8VhPG-lDhrGZdv`Ju1I^{Nx)3a<2qed}DSz8Hl@lBD>1g>(gOnb=e{z zOY8=pU#8e32mE}esEdcev0PrGSu*^PF&|@TaiOF;x1NpU8N%4U&(-#S%M)cXRE}kG zgD>$YNmg5@ko-s#bSXC75&8k|pk0iNIm^1-tG#->X8MKT`Q9PDaffpsmT&djX)ij# z7^kmMM@i_9y?%R>%dAgL6=Q7*{+Vs^N(=A~6zv50$+(*Y?G#;$0%W6Vm$wA{biH=0 zV5%$}m~u~4gunLbQam`njD~wL`KGDA+|H?Yl$8*t?5|+$LH`|~{xur??RXj;RZfFJ zd9h#OR~Yy$0s8fqw+*^nrTqBZE`6=O6#!9j%w?U^Y0SGpc_>ST9W>2L#urZJ*5T}o zVNV8|oRG9Nt%hhc>cihlN{s!>po-9%ZR5#^o+L98ckqO5E-9Go-c;Sunk>2j;#xZJ zJ9U`_AkKmC*Sb3GM81gUw_+TgGM0kL#O%UYbdoQBLN#TMbwoi(#+GeOm~qbghTy>} zs3u$#t}k_jOO!AKc+>bUzXEWWgOok9MwMM~vbrO_|8YAUrv)=XFs%lL#8p&G1YSum z%|Jw<`UcI-N#8N}7tO?f4Ombm&K_up+IO@0Bl3Jpi)w&_cqniq{@(9{`oGTl*RSAx z;l}lCgYU*!{_=kR$$BN$18^{EM=h3LlHQ+F<*yF-J^*B%506LX?=kZK3}PN!7MFT- zis}CN_ka=th{;R6@bK`;E&h*s91*?`-B=V|!d6MvU;SHu^7pWZSOBKCpEftR_s3=b zYWcs;`Eep4cNhAL+GQ14KoO&tEkt;et>m_V(NbX+N-9W0^!ELo}T~v zom(AIu?-V~L4SD$2+;W*bQ4LzzPFYm6>Rdf>nuToNvjK%_P zFkh1t&_P+nX2tTo>%Sn}kIfb9;b=?#j_z16S!Jutv9AZwr*}Nhzf6XHUF-_VzkcM4 zB}u9~n^LPyloJs+pr~NcvSCo zw(#K{vFQ+nZ3hTZ*=icPtNp+hy}*zM7~PT5M*Wz`7pN!8N;EJo6wz;yXHVG=mz7r61O=H{^=l-#jW!H{eE&Wu z7DTQW=Fz66rXmB`-90XlAof@znNk5;V+N>&lFlqIPWsGJx92L16~;`z+?>3aT*oFL zhykISsUWmIU>ezh35*+`)MZTTCY=C&`3(Xp#2egiNqYJ zQSg2$^4cEXm55Hbn|G$jk;C5yj9%q1boII%%{zNji2wE<@X@0UvsB+&-#GV&V>=){ z+oEGQKW%$4$w#s<0uSj*Nagga@O4d?!?Hy4aZ0ZHR7leAj>xpa%HW&)Mcf>FlPg zE8ihaO*?Z%KzoCfZ%Yy#_q|@aA`Xbi$W{&JD?p;=r1ifa@IRl7e1cl-{Kk9Y zu2Y7=2^B&pi?-C?0cm}n0AY@uOlcfdTqi)y8fzlXiY;g-`FLK~P^vw(~=LSN9O ztGLRT=;lq(pg=1^z-jGmCSSkerNfoUaNCEHZ@6@qyipD4=)Q|SWsX|;%YiLW8KW}< zedTUHv}+vAF-UtelCPuAq?OMAf+4)gzKcc>!7PHN*5!!X4`2mA_HkGX@@Ba~mFLet z=bU|@`!vQjQmC&RM9OY6W%0&uSDMqsGrX|Y}mA6vDzwsrt>Qd6is%i}MX zDZI+vyB`r=Oy)+$^KEz~^MRCyaXm+4lx(_#}dOX%$WI-0! zTRu`6-9(-<0fHtvI=WEqm#-qo#vNw8lgll~$V;yawiqO1XRYjlD6M<)qA-f9Au-&t zuv!|RMofS{V4qv1;KXnL!@mx6ujMyQcDsMHHANqAjkLnRyf2~Ht56rJ+?OOsKW5-j zz->LLQCPbtpY;xkJDR2bD0w+M`{47@J#KD|m*4X5oeD*<=}&rB@>tfF9_b~kgVc5N zV^RHSS0O3u(-D!gn(q)Q1l7g)G7hLdrk7bvjf&`2grCUv*Qr(RCrzzt$DB@`H%)hg z+1>#F=Zv^&(lzy#a}m@V5MAq1_XE-r$9CoF4143FGmEMG)0wL^_=k7ws#TBn!{sq4o4HU4*NtLZ^a-Qy6~V|6296%V)3L}x3Eg4U9rY1E0Q40MpQ(^ zz^w1nouazKT=ib_9FzfUV&q+(9!^>*w0KZe4VNe`W{f+a<`4sBfE&b5R5-{84Up@G zrla{TY9nKm+x><{X!R%rr<=D$Z4!E7iI2TjE=w3=^vY$A^s^>Fq2zuYwfDG8zX^r5^@C#n@(P*3^XbRrVEUlDi{vX>)txMDO>=TWJ9 z5EWw>4MtjbdZ)V8l`4gpKE^FuDXtEquE-paF*(c`3f|(g$(JlJWG4_AS9l|eD4WX4 zOi1Q5Euj?R-2K3pE)%-NI0RciQ0DbodyQg?J(`8D==$T`MJbv@?Lp!}!Bj;z(DN+J zI+{1Q^PAz3^F~%XI@yJ8mjlcL^liJn${oI52<^kz=W;0Gbg&Ut)zeEj(A`_j+H$L7 zcA0gGSt(6HQ?31KnO8Kwa$ux#N!luKU_&P0t(Y%v_j%Zi68_wL|7@jj$P_EYUtwMq zc53UMtb?0uCRLj;TbR|m=+wW^ufCHXzrx8EIZ9ix*~xXok9QKXVAvmnS7q5mF3 znIfKSBLL@SN$G2_{4ri|mDUQD+0s*=8;2*>Z8=AG1@$>Nqqb=4J4Kak4?GHbb2Ey) zXJf9{4CA;gN8Nh8or>beAt#s|e4il0y?outHpqwsUal;VyApA8tn(h~+WVde+)AyF zy=Rzdr87td14N1_tMQ$>+P$uB=P+MGE-1fuv+IPdS#Vxd-_pg&LjV0QXGy}mU{$XE zeo7%()UV6^zAU!;iN4CC_wsquBII3;J zE>ijgTzpSJH|gX$bC@T*oDx074@WxW)}8J8m{-*2Q>V5BK)_wIjszUuiJt52Ayg6U zN=ul+q0zwgMMquV5VSOAOPB2YXg2Dhc8KNWeBKRYASM8aa<0V39W?J`B&*gY<3Acq zlgT*Hcd7Al^}>G{{|Nmlx1%pIDVkl^3=#9mgNPxb=>)#J2l()lBHU6Rr-7<1 z>8h?S)enTs`-Vi#)uJq~ziQiG-3p$Up;|RoZ}*^13>7`?z*`cXhF0QIo>uAEOYO0a zh+P1X!ivUjdc2sk9lZd)&^f<(_iIg`b7=5w>my6|L!DA{1vz4dZ=8+jPunG>yP5+a zm5&gh_*=!bNXn-7V!aGF>9xg?9nOA!^h7BlY4&qzYqIw#nZ@AefGJ7yLCeSRGy>5` zm7DCm>-|&Q8#V#gn90MohO>%<%u233WJC%I@4POvoN62WWQrl{igp^;H;cVg`C?)S zpJd=lZFEzp2ou03c~G`UH=LzK_YA_d!TxAcXqp|#pxSIbTRdOq(4V|rF-0BgaokF* zQqv9`ofk0RPK}a4(l_G)`c0;Bx{oj%#oAF^eR9&9UVpJN|5dHd-N~cOumNf2?4?2> z=G|iQaDa&4EO;6Mp@$Yyv)3JeraVtUad6sA&e+yc1aZbt|8(pzn&SOHLfWLtBSlQ< zmGvuYr+D(a+iTzs+HhQC#I(r=hEUEhwe)bMpb?ajFcPid3slXAOl{JHBni9A!@LpG zr$}ajPmhvU$+*lXmsK%U{QdpMU;Z|RD$NS)%)T|8cQHF0%|M*lyW`2kxt`U+`+7i$ zVIPL-bsxq>hDjdRgEpyLq_3cb+?u{-{MX^lWpqN*jzcF^>9DbQwf+l_XkV1n`kU^0 zV~QTZ@~

    ag9i6iZ5d+UT3Go8}0$molFgI%~tV38Uy4L(_-eBe0ujfHdgx z)iKBM&czVfelRcwHGrUu>Z! z#(4c@%>3I6{0cN5!hj*l+Jwbr-qR$BR2RVDD}7pVq0=v5F?gd}}9O zSecNVa29APv@{aUBJnyp2i_oCeY`G(3g(=GT#&Q4*A09->m!4vS;_=e@lfyS#X?No zL7kDO+%Kj9*@nVsgeDEH4K$+I4cE(H=4LIHoynpN&~0Gn6a_)7Cp+IP7XI{(VB2MI zJKJXv0zp=vn}1`ftTetK<(Bf9Dr}HrND8wt1tKVUb>TuOJ?zp-t0Mz0+Z8M7;>$xtq-AoY;}*$ zRqs`W$YVPx+1MXPjgwGA@Vi_#~ zD2%hlItVEIuvg%(a~SYE#QI2N`^J*Eiu#vx>nFlVdiVyd9uS%&)~vA|QBBOLYxBKY z@@_s!cMrfBi~6w$Rd`go&rUuLbAFmWs(D8Z&NRHd{rDAcUFMUEueB})>WeDL$O_^0 zfm8{T!OsMnf-`k7#emi4qHgYq$$YA8=@0>4;hO9Q)dwP&|#QWP5@JE+k?Gyt_oiyCUmI*rE*Mqn?l#MVARgh8;o$)Y5_@ZTkkaiemApY8 zzfK)YHE7mlGwVENkAB4eYwYUdncUlW6mmLJB2lCiMOo33x6ymvJ0XuG>p5&*^Ugur zyi_6~H|r#BdIcHmstf<7B0N>1n*j3c-P6 z2}Zd3xv%bZ5j1f*`TpxixKFgxDi9NdlmdT*tM&)MZ&++VR(KYAzOHnbzq1VesQhcm z^+j2UcmY$WIw1BEdo$20&YW347l=b+vaNO%@e8z4lpoOQNiB|D`bDd&5o2`wl=nT- zEaXOWz4#_>CS94yLa!_Z;Y6_~(_5qvI$Gln#>7_1oZrG{&+@d~ z8Y#yJF2vGhpF7{b{_%cn3&AjOFbW9>Ti+%koHsiHW)%f5zGtny1DWLAdjV!hxRzsp ztOF5C0FupTce}ydsvSWuFnYCj`E85$VvE0i2%&i)aY(IADhlmJ_)<4!~gE2=vNb6=5S_d+g$+CKP#4yPvrTWwn@` zkIsX;cFiLGx)GYL{@dH{mMtY!|WumWuF)2cHcJG zUN1vVqSVtBr><2sjHx!+%)G%9L1#if^Lp=#GM@5th}@k8<=#%qv? z>%dW)HPX0J!RIZ+=2|&8_{OEgbol^e-&c^LwGsjUFL6VYgT>r9QJmYk#k<9-6QDwA=bdrdr<`X;lAY@=RxvB@Udi-)u!H0%$lH#%3}WWz>)p1#XepIq-}vw zwi`^A4d>e$r1(z1(bi>7MB5|2lWZgRCxeM|om;==<)-IGk3P|^ z4WUZWT^}vjXenYB{a3h0efGJFTz(W_HiMj~eHj3+mfA_$`D3tlM8~QZ|2!CJ;d3MA0O_){EwX zr1*Bba5XO`*G#Lj0S#;gd;S>@7BZIXRmhT!Gv|_t>4VV>|BGYAAdh|PYRov8Dq7mb zm(Kdt1`g8?u33N*HU=h1^M^Z1*VoeA*-jnhREu>KnK}SO#~+ag}5@kA)YC3&Q_;(BpH~vy6>GEDLTKF zOCK^FBsXJ1=Z0h4KwbVNX>;Lov(m{WT-3ZJ?)RVbTHpf?_R@aQ4eXWRMIV(DfidR- zShMJZs8ZO!a-NLrD*_mxjkAv1uFc=O3|W`_{E|^TNjb`#_culdxg|KSEc}*PKNxH0 z8YZaroL`t537+?ux7ekYLu{GXwtOu)+*6P#?Mg|Qezn)F*i4BeQck;AaNP}?zeA3{{69Id-bd4vKt$PLObD&7WH%&BJ(A&jw9fHzEb32c^J?N zp;+}HeG#965<({j`xrK1co&I3&ZRs;i-d!YqBjZhJ4B%CzYc8SceX4J*^f>Mjk#NT zfA6Wnwwb1=hpNGFF`86WTHDso`FWPicb2(!h&)EbNg3FozX$$*sZljPloSCjG? zbk$+!RB5^0gZ$UanCt?xy_xprg8!h$K_~G2Rj0~pUDD;yu;|=s&l1nhs|@}6cJVd6 zx8cpQ%xSZJ^ROPp1!m@g@RMjV%k{QiCCG_a53ayM;nrKY$zCQXX{Zw>$_l}G%)|CK zEb}>#X?kTw*mVD3bZPvRh1`A)o*L&+5ap8tzP9feHgx?8bi|~w%H#iEuD@qEg6~*V zKH$owha%WYS>%C9U;DKI}Xs;fA%bcJ-o zQ!UcaW%*t3Y45<0?_b`AyP4n1b!iK*$K8y-(^z@h)^@V$e0-ZwZ<&4rcZd?nmf&tz z2)?Np??P{vU>2!JWE~NarLkC1)D5{qzTF#^wm_OE_9&=rqP3ot;VW%W-4!ua=M&aM zj>fctQ0r|aZt%lI_oE(Qmq|$m(G4Nldiu9kHbr3WkLPi}S*jO}eCAv|sk?7qJL+9N z8d^A|C|Bci%w6VqvtZ1%Xrt_tFJ{?92(9`;SDwE2yrRjgGpQ8`yoz=KiCLg$_$jd1 zKZ_o+H}oP%jf}=)j_9k%8xMRHKIJ<_9cr!a<2HtEZnu!fk zYK7d(F*e&$oR19we24L1WaIh=^WBzj$MHQGWu$Rhry9)UuoMabAyC|OOI`#t_k=5j zo%BpKcExyArYqdgu!zs>gG?5z)uF(jGS8@O+NP=+)lDzPFGC-TK^Mh-Ppj;#9x#&t zls(7sD)1Dj6Y6Er`I75``P|lf_4TJ1$hZRF&1a}0>T1P>@rBBP+hr6K6xc?odyM`~ zadAshZ1~L_JK4ta(4{R*(XUpFNiX$=9Ci zu=O{4wY`S(rUl#+#ziSyHIV|D?8!-E8?rKhPfg6 z14)@8^CP#1tli!PrCf)z%hViK@O)>qFAdjMzmTx5W&ATGmUd7Q(-DKt>gbmJ=O=BD zWE|R-{t(p*{gMA}_P7!ggVq}Hy7$jw#8`y?w2el!a}!?p`$y+*tE7=3xoN>b_M*YM zZt4Fve6<6RB7CaH@JD3MRn#cNS)R(@_K{jSCNdL~&YDnv$L~;6uEiBA40#BU% ekrgqKTHPzzgI_-B*~r`gewOF$&Q+a($Nd-f&95*3 literal 0 HcmV?d00001 diff --git a/docs/tutorials/microsoft365/img/app-overview.png b/docs/tutorials/microsoft365/img/app-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..1a2cf7b2ab8c4f6a58c01fc397ae27404ef9f5a4 GIT binary patch literal 337670 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

    wd{Wa7o`@?>o%6 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 }z`h*h14 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 z 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 literal 763824 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%0D^#F^oX{NNH(l`H~954<8VGOU)xLh)FbH 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⁡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�?!d(s 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 z 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

    """ diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py index f5011c9c27..2b766171e6 100644 --- a/prowler/providers/m365/m365_provider.py +++ b/prowler/providers/m365/m365_provider.py @@ -207,6 +207,7 @@ class M365Provider(Provider): m365_credentials=m365_credentials, provider_id=self.identity.tenant_domain, init_modules=init_modules, + identity=self.identity, ) # Audit Config @@ -382,6 +383,7 @@ class M365Provider(Provider): m365_credentials: dict = {}, provider_id: str = None, init_modules: bool = False, + identity: M365IdentityInfo = None, ) -> M365Credentials: """Gets the M365 credentials. @@ -394,6 +396,7 @@ class M365Provider(Provider): If False, returns empty credentials. """ credentials = None + if m365_credentials: credentials = M365Credentials( user=m365_credentials.get("user", ""), @@ -428,6 +431,9 @@ class M365Provider(Provider): ) if credentials: + if identity: + identity.identity_type = "Service Principal and User Credentials" + identity.user = credentials.user test_session = M365PowerShell(credentials) try: if test_session.test_credentials(credentials): diff --git a/prowler/providers/m365/models.py b/prowler/providers/m365/models.py index a2e3b68151..198c54e33e 100644 --- a/prowler/providers/m365/models.py +++ b/prowler/providers/m365/models.py @@ -10,6 +10,7 @@ class M365IdentityInfo(BaseModel): tenant_id: str = "" tenant_domain: str = "Unknown tenant domain (missing AAD permissions)" location: str = "" + user: str = None class M365RegionConfig(BaseModel): diff --git a/tests/lib/outputs/html/html_test.py b/tests/lib/outputs/html/html_test.py index 2bc6d9ab07..9ee634dc0f 100644 --- a/tests/lib/outputs/html/html_test.py +++ b/tests/lib/outputs/html/html_test.py @@ -12,6 +12,7 @@ from tests.providers.gcp.gcp_fixtures import GCP_PROJECT_ID, set_mocked_gcp_prov from tests.providers.kubernetes.kubernetes_fixtures import ( set_mocked_kubernetes_provider, ) +from tests.providers.m365.m365_fixtures import set_mocked_m365_provider html_stats = { "total_pass": 25, @@ -222,6 +223,38 @@ kubernetes_html_assessment_summary = """
    """ +m365_html_assessment_summary = """ +
    +
    +
    + M365 Assessment Summary +
    +
      +
    • + M365 Tenant Domain: user.onmicrosoft.com +
    • +
    +
    +
    +
    +
    +
    + M365 Credentials +
    +
      +
    • + M365 Identity Type: Application +
    • +
    • + M365 Identity ID: 00000000-0000-0000-0000-000000000000 +
    • +
    • + M365 User: user@email.com +
    • +
    +
    +
    """ + def get_aws_html_header(args: list) -> str: """ @@ -554,3 +587,13 @@ class TestHTML: summary = output.get_assessment_summary(provider) assert summary == kubernetes_html_assessment_summary + + def test_m365_get_assessment_summary(self): + findings = [generate_finding_output()] + output = HTML(findings) + provider = set_mocked_m365_provider() + + summary = output.get_assessment_summary(provider) + + expected_summary = m365_html_assessment_summary + assert summary == expected_summary diff --git a/tests/providers/m365/m365_fixtures.py b/tests/providers/m365/m365_fixtures.py index 0eb3c203e1..f985f94b6a 100644 --- a/tests/providers/m365/m365_fixtures.py +++ b/tests/providers/m365/m365_fixtures.py @@ -29,6 +29,7 @@ def set_mocked_m365_provider( identity_type=IDENTITY_TYPE, tenant_id=TENANT_ID, tenant_domain=DOMAIN, + user="user@email.com", ), audit_config: dict = None, azure_region_config: M365RegionConfig = M365RegionConfig(), From a19f5d9a9a69fbb95bee8cb585f36e81adbf1db0 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Mon, 12 May 2025 15:07:44 +0200 Subject: [PATCH 296/359] feat: scan label validation (#7693) --- .../launch-scan-workflow-form.tsx | 94 ++++++++++--------- ui/components/ui/custom/custom-input.tsx | 2 +- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx b/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx index 9937b5cc9d..74bfbf8fde 100644 --- a/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx +++ b/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx @@ -26,8 +26,16 @@ export const LaunchScanWorkflow = ({ }: { providers: ProviderInfo[]; }) => { - const formSchema = onDemandScanFormSchema(); - const form = useForm>({ + const formSchema = z.object({ + ...onDemandScanFormSchema().shape, + scanName: z + .string() + .min(3, "Must have at least 3 characters") + .or(z.literal("")) + .optional(), + }); + + const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { providerId: "", @@ -77,25 +85,25 @@ export const LaunchScanWorkflow = ({
    -
    -
    - -
    - - {form.watch("providerId") && ( - <> +
    + +
    + + {form.watch("providerId") && ( + <> +
    -
    - } - > - {isLoading ? <>Loading : Start now} - - form.reset()} - className="w-fit border-gray-200 bg-transparent" - ariaLabel="Clear form" - variant="bordered" - size="sm" - radius="sm" - > - Cancel - -
    + } + > + {isLoading ? <>Loading : Start now} + + form.reset()} + className="w-fit border-gray-200 bg-transparent" + ariaLabel="Clear form" + variant="bordered" + size="sm" + radius="sm" + > + Cancel +
    - - )} - - {/* +
    + + )} +
    + {/*
    {form.watch("providerId") && ( @@ -169,7 +176,6 @@ export const LaunchScanWorkflow = ({ )}
    */} -
    ); diff --git a/ui/components/ui/custom/custom-input.tsx b/ui/components/ui/custom/custom-input.tsx index 3979c459f3..5b76ef6fda 100644 --- a/ui/components/ui/custom/custom-input.tsx +++ b/ui/components/ui/custom/custom-input.tsx @@ -120,7 +120,7 @@ export const CustomInput = ({ /> {showFormMessage && ( - + )} )} From 44f26bc0d587fa1fab448582ce76fb804823ca24 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Mon, 12 May 2025 09:23:14 -0400 Subject: [PATCH 297/359] chore(docs): quality redrive to README.md (#7616) Co-authored-by: dcanotrad <168282715+dcanotrad@users.noreply.github.com> Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- README.md | 154 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 107 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 15763cb4b0..13c10cdd1c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

    - Prowler Open Source is as dynamic and adaptable as the environment they’re meant to protect. Trusted by the leaders in security. + Prowler Open Source is as dynamic and adaptable as the environment it secures. It is trusted by the industry leaders to uphold the highest standards in security.

    Learn more at prowler.com @@ -43,15 +43,29 @@ # Description -**Prowler** is an Open Source security tool to perform AWS, Azure, Google Cloud and Kubernetes security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness, and also remediations! We have Prowler CLI (Command Line Interface) that we call Prowler Open Source and a service on top of it that we call Prowler Cloud. +**Prowler** is an open-source security tool designed to assess and enforce security best practices across AWS, Azure, Google Cloud, and Kubernetes. It supports tasks such as security audits, incident response, continuous monitoring, system hardening, forensic readiness, and remediation processes. + +Prowler includes hundreds of built-in controls to ensure compliance with standards and frameworks, including: + +- **Industry Standards:** CIS, NIST 800, NIST CSF, and CISA +- **Regulatory Compliance and Governance:** RBI, FedRAMP, and PCI-DSS +- **Frameworks for Sensitive Data and Privacy:** GDPR, HIPAA, and FFIEC +- **Frameworks for Organizational Governance and Quality Control:** SOC2 and GXP +- **AWS-Specific Frameworks:** AWS Foundational Technical Review (FTR) and AWS Well-Architected Framework (Security Pillar) +- **National Security Standards:** ENS (Spanish National Security Scheme) +- **Custom Security Frameworks:** Tailored to your needs + +## Prowler CLI and Prowler Cloud + +Prowler offers a Command Line Interface (CLI), known as Prowler Open Source, and an additional service built on top of it, called Prowler Cloud. ## Prowler App -Prowler App is a web application that allows you to run Prowler in your cloud provider accounts and visualize the results in a user-friendly interface. +Prowler App is a web-based application that simplifies running Prowler across your cloud provider accounts. It provides a user-friendly interface to visualize the results and streamline your security assessments. ![Prowler App](docs/img/overview.png) ->More details at [Prowler App Documentation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-app-installation) +>For more details, refer to the [Prowler App Documentation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-app-installation) ## Prowler CLI @@ -60,6 +74,7 @@ prowler ``` ![Prowler CLI Execution](docs/img/short-display.png) + ## Prowler Dashboard ```console @@ -67,7 +82,7 @@ prowler dashboard ``` ![Prowler Dashboard](docs/img/dashboard.png) -It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks. +# Prowler at a Glance | Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | |---|---|---|---|---| @@ -78,15 +93,16 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe | M365 | 44 | 2 | 2 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | -> You can list the checks, services, compliance frameworks and categories with `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`. +> Use the following commands to list Prowler's available checks, services, compliance frameworks, and categories: `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`. # 💻 Installation ## Prowler App -Prowler App can be installed in different ways, depending on your environment: +Installing Prowler App +Prowler App offers flexible installation methods tailored to various environments: -> See how to use Prowler App in the [Prowler App Usage Guide](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/). +> For detailed instructions on using Prowler App, refer to the [Prowler App Usage Guide](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/). ### Docker Compose @@ -102,8 +118,16 @@ curl -LO https://raw.githubusercontent.com/prowler-cloud/prowler/refs/heads/mast docker compose up -d ``` -> Containers are built for `linux/amd64`. If your workstation's architecture is different, please set `DOCKER_DEFAULT_PLATFORM=linux/amd64` in your environment or use the `--platform linux/amd64` flag in the docker command. -> Enjoy Prowler App at http://localhost:3000 by signing up with your email and password. +> Containers are built for `linux/amd64`. + +### Configuring Your Workstation for Prowler App + +If your workstation's architecture is incompatible, you can resolve this by: + +- **Setting the environment variable**: `DOCKER_DEFAULT_PLATFORM=linux/amd64` +- **Using the following flag in your Docker command**: `--platform linux/amd64` + +> Once configured, access the Prowler App at http://localhost:3000. Sign up using your email and password to get started. ### From GitHub @@ -129,12 +153,12 @@ python manage.py migrate --database admin gunicorn -c config/guniconf.py config.wsgi:application ``` > [!IMPORTANT] -> Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`. +> As of Poetry v2.0.0, the `poetry shell` command has been deprecated. Use `poetry env activate` instead for environment activation. > -> If your poetry version is below 2.0.0 you must keep using `poetry shell` to activate your environment. -> In case you have any doubts, consult the Poetry environment activation guide: https://python-poetry.org/docs/managing-environments/#activating-the-environment +> If your Poetry version is below v2.0.0, continue using `poetry shell` to activate your environment. +> For further guidance, refer to the Poetry Environment Activation Guide https://python-poetry.org/docs/managing-environments/#activating-the-environment. -> Now, you can access the API documentation at http://localhost:8080/api/v1/docs. +> After completing the setup, access the API documentation at http://localhost:8080/api/v1/docs. **Commands to run the API Worker** @@ -172,29 +196,31 @@ npm run build npm start ``` -> Enjoy Prowler App at http://localhost:3000 by signing up with your email and password. +> Once configured, access the Prowler App at http://localhost:3000. Sign up using your email and password to get started. ## Prowler CLI ### Pip package -Prowler CLI is available as a project in [PyPI](https://pypi.org/project/prowler-cloud/), thus can be installed using pip with Python > 3.9.1, < 3.13: +Prowler CLI is available as a project in [PyPI](https://pypi.org/project/prowler-cloud/). Consequently, it can be installed using pip with Python >3.9.1, <3.13: ```console pip install prowler prowler -v ``` ->More details at [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-cli-installation) +>For further guidance, refer to [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-cli-installation) ### Containers -The available versions of Prowler CLI are the following: +**Available Versions of Prowler CLI** -- `latest`: in sync with `master` branch (bear in mind that it is not a stable version) -- `v4-latest`: in sync with `v4` branch (bear in mind that it is not a stable version) -- `v3-latest`: in sync with `v3` branch (bear in mind that it is not a stable version) -- `` (release): you can find the releases [here](https://github.com/prowler-cloud/prowler/releases), those are stable releases. -- `stable`: this tag always point to the latest release. -- `v4-stable`: this tag always point to the latest release for v4. -- `v3-stable`: this tag always point to the latest release for v3. +The following versions of Prowler CLI are available, depending on your requirements: + +- `latest`: Synchronizes with the `master` branch. Note that this version is not stable. +- `v4-latest`: Synchronizes with the `v4` branch. Note that this version is not stable. +- `v3-latest`: Synchronizes with the `v3` branch. Note that this version is not stable. +- `` (release): Stable releases corresponding to specific versions. You can find the complete list of releases [here](https://github.com/prowler-cloud/prowler/releases). +- `stable`: Always points to the latest release. +- `v4-stable`: Always points to the latest release for v4. +- `v3-stable`: Always points to the latest release for v3. The container images are available here: - Prowler CLI: @@ -206,7 +232,7 @@ The container images are available here: ### From GitHub -Python > 3.9.1, < 3.13 is required with pip and poetry: +Python >3.9.1, <3.13 is required with pip and Poetry: ``` console git clone https://github.com/prowler-cloud/prowler @@ -216,25 +242,46 @@ poetry install python prowler-cli.py -v ``` > [!IMPORTANT] -> Starting from Poetry v2.0.0, `poetry shell` has been deprecated in favor of `poetry env activate`. -> -> If your poetry version is below 2.0.0 you must keep using `poetry shell` to activate your environment. -> In case you have any doubts, consult the Poetry environment activation guide: https://python-poetry.org/docs/managing-environments/#activating-the-environment +> To clone Prowler on Windows, configure Git to support long file paths by running the following command: `git config core.longpaths true`. -> If you want to clone Prowler from Windows, use `git config core.longpaths true` to allow long file paths. -# 📐✏️ High level architecture +> [!IMPORTANT] +> As of Poetry v2.0.0, the `poetry shell` command has been deprecated. Use `poetry env activate` instead for environment activation. +> +> If your Poetry version is below v2.0.0, continue using `poetry shell` to activate your environment. +> For further guidance, refer to the Poetry Environment Activation Guide https://python-poetry.org/docs/managing-environments/#activating-the-environment. + +# ✏️ High level architecture ## Prowler App -The **Prowler App** consists of three main components: +**Prowler App** is composed of three key components: -- **Prowler UI**: A user-friendly web interface for running Prowler and viewing results, powered by Next.js. -- **Prowler API**: The backend API that executes Prowler scans and stores the results, built with Django REST Framework. -- **Prowler SDK**: A Python SDK that integrates with the Prowler CLI for advanced functionality. +- **Prowler UI**: A web-based interface, built with Next.js, providing a user-friendly experience for executing Prowler scans and visualizing results. +- **Prowler API**: A backend service, developed with Django REST Framework, responsible for running Prowler scans and storing the generated results. +- **Prowler SDK**: A Python SDK designed to extend the functionality of the Prowler CLI for advanced capabilities. ![Prowler App Architecture](docs/img/prowler-app-architecture.png) ## Prowler CLI -You can run Prowler from your workstation, a Kubernetes Job, a Google Compute Engine, an Azure VM, an EC2 instance, Fargate or any other container, CloudShell and many more. + +**Running Prowler** + +Prowler can be executed across various environments, offering flexibility to meet your needs. It can be run from: + +- Your own workstation + +- A Kubernetes Job + +- Google Compute Engine + +- Azure Virtual Machines (VMs) + +- Amazon EC2 instances + +- AWS Fargate or other container platforms + +- CloudShell + +And many more environments. ![Architecture](docs/img/architecture.png) @@ -242,23 +289,36 @@ You can run Prowler from your workstation, a Kubernetes Job, a Google Compute En ## General - `Allowlist` now is called `Mutelist`. -- The `--quiet` option has been deprecated, now use the `--status` flag to select the finding's status you want to get from PASS, FAIL or MANUAL. -- All `INFO` finding's status has changed to `MANUAL`. -- The CSV output format is common for all the providers. +- The `--quiet` option has been deprecated. Use the `--status` flag to filter findings based on their status: PASS, FAIL, or MANUAL. +- All findings with an `INFO` status have been reclassified as `MANUAL`. +- The CSV output format is standardized across all providers. -We have deprecated some of our outputs formats: -- The native JSON is replaced for the JSON [OCSF](https://schema.ocsf.io/) v1.1.0, common for all the providers. +**Deprecated Output Formats** + +The following formats are now deprecated: +- Native JSON has been replaced with JSON in [OCSF] v1.1.0 format, which is standardized across all providers (https://schema.ocsf.io/). ## AWS -- Deprecate the AWS flag --sts-endpoint-region since we use AWS STS regional tokens. -- To send only FAILS to AWS Security Hub, now use either `--send-sh-only-fails` or `--security-hub --status FAIL`. + +**AWS Flag Deprecation** + +The flag --sts-endpoint-region has been deprecated due to the adoption of AWS STS regional tokens. + +**Sending FAIL Results to AWS Security Hub** + +- To send only FAILS to AWS Security Hub, use one of the following options: `--send-sh-only-fails` or `--security-hub --status FAIL`. # 📖 Documentation -Install, Usage, Tutorials and Developer Guide is at https://docs.prowler.com/ +**Documentation Resources** + +For installation instructions, usage details, tutorials, and the Developer Guide, visit https://docs.prowler.com/ # 📃 License -Prowler is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at - +**Prowler License Information** + +Prowler is licensed under the Apache License 2.0, as indicated in each file within the repository. Obtaining a Copy of the License + +A copy of the License is available at From 70e22af550edf34dac30ed29a13bca6891910709 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 12 May 2025 16:09:54 +0200 Subject: [PATCH 298/359] chore(deps): upgrade recharts from 2.13.0-alpha.4 to 2.15.2 (#7717) --- ui/package-lock.json | 35 ++++++++++++++++++++--------------- ui/package.json | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index f0a11642d6..f86d6169d2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -43,7 +43,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.2", - "recharts": "^2.13.0-alpha.4", + "recharts": "^2.15.2", "server-only": "^0.0.1", "shadcn-ui": "^0.2.3", "sharp": "^0.33.5", @@ -9420,6 +9420,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -10402,9 +10403,10 @@ "dev": true }, "node_modules/fast-equals": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", - "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -13363,17 +13365,18 @@ } }, "node_modules/react-smooth": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", - "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-style-singleton": { @@ -13419,6 +13422,7 @@ "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -13463,15 +13467,16 @@ } }, "node_modules/recharts": { - "version": "2.13.0-alpha.4", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.0-alpha.4.tgz", - "integrity": "sha512-K9naL6F7pEcDYJE6yFQASSCQecSLPP0JagnvQ9hPtA/aHgsxsnIOjouLP5yrFZehxzfCkV5TEORr7/uNtSr7Qw==", + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.3.tgz", + "integrity": "sha512-EdOPzTwcFSuqtvkDoaM5ws/Km1+WTAO2eizL7rqiG0V2UVhTnz0m7J2i0CjVPUCdEkZImaWvXLbZDS2H5t6GFQ==", + "license": "MIT", "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", - "react-smooth": "^4.0.0", + "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" @@ -13480,8 +13485,8 @@ "node": ">=14" }, "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/recharts-scale": { diff --git a/ui/package.json b/ui/package.json index 25a1cdfb1a..13a4ae147e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -35,7 +35,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.2", - "recharts": "^2.13.0-alpha.4", + "recharts": "^2.15.2", "server-only": "^0.0.1", "shadcn-ui": "^0.2.3", "sharp": "^0.33.5", From 16f2209d3f333423cac7b343d7316aab28578da4 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 12 May 2025 16:20:07 +0200 Subject: [PATCH 299/359] chore: add M365 to scan page filters (#7704) --- ui/components/filters/data-filters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/filters/data-filters.ts b/ui/components/filters/data-filters.ts index ca09af434d..8d712bfb70 100644 --- a/ui/components/filters/data-filters.ts +++ b/ui/components/filters/data-filters.ts @@ -11,7 +11,7 @@ export const filterScans = [ { key: "provider_type__in", labelCheckboxGroup: "Cloud Provider", - values: ["aws", "azure", "gcp", "kubernetes"], + values: ["aws", "azure", "m365", "gcp", "kubernetes"], }, { key: "state__in", From 1a8df3bf188b34813b18b541345a569965613f03 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 12 May 2025 17:02:30 +0200 Subject: [PATCH 300/359] fix(defender): enhance policies checks logic (#7666) Co-authored-by: Daniel Barranquero Co-authored-by: MrCloudSec --- .../m365/lib/powershell/m365_powershell.py | 20 + ...defender_antiphishing_policy_configured.py | 176 ++++- ...der_antispam_outbound_policy_configured.py | 176 ++++- ...pam_outbound_policy_forwarding_disabled.py | 162 ++++- ...ispam_policy_inbound_no_allowed_domains.py | 169 ++++- ...olicy_common_attachments_filter_enabled.py | 139 +++- ...omprehensive_attachments_filter_applied.py | 207 ++++-- ...ications_internal_users_malware_enabled.py | 167 ++++- .../services/defender/defender_service.py | 94 ++- ...der_antiphishing_policy_configured_test.py | 477 +++++++++---- ...ntispam_outbound_policy_configured_test.py | 493 +++++++++---- ...utbound_policy_forwarding_disabled_test.py | 668 ++++++++++++------ ..._policy_inbound_no_allowed_domains_test.py | 318 ++++++++- ..._common_attachments_filter_enabled_test.py | 370 +++++++++- ...hensive_attachments_filter_applied_test.py | 613 ++++++++++------ ...ons_internal_users_malware_enabled_test.py | 379 ++++++++-- .../defender/m365_defender_service_test.py | 134 +++- 17 files changed, 3766 insertions(+), 996 deletions(-) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index fead633b6d..f32921b001 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -525,6 +525,26 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + def get_inbound_spam_filter_rule(self) -> dict: + """ + Get Inbound Spam Filter Rule. + + Retrieves the current inbound spam filter rule settings for Exchange Online. + + Returns: + dict: Inbound spam filter rule settings in JSON format. + + Example: + >>> get_inbound_spam_filter_rule() + { + "Name": "Rule1", + "State": "Enabled" + } + """ + return self.execute( + "Get-HostedContentFilterRule | ConvertTo-Json", json_parse=True + ) + def get_report_submission_policy(self) -> dict: """ Get Exchange Online Report Submission Policy. diff --git a/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py index 18ac8f9949..61727b9d3c 100644 --- a/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py +++ b/prowler/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured.py @@ -23,37 +23,155 @@ class defender_antiphishing_policy_configured(Check): List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - for policy_name, policy in defender_client.antiphishing_policies.items(): - report = CheckReportM365( - metadata=self.metadata(), - resource=policy, - resource_name="Defender Anti-Phishing Policy", - resource_id=policy_name, - ) - report.status = "FAIL" - report.status_extended = ( - f"Anti-phishing policy {policy_name} is not properly configured." - ) - if ( - not policy.default - and policy_name in defender_client.antiphising_rules - and defender_client.antiphising_rules[policy_name].state.lower() - == "enabled" - ) or policy.default: - if ( - policy.spoof_intelligence - and policy.spoof_intelligence_action.lower() == "quarantine" - and policy.dmarc_reject_action.lower() == "quarantine" - and policy.dmarc_quarantine_action.lower() == "quarantine" - and policy.safety_tips - and policy.unauthenticated_sender_action - and policy.show_tag - and policy.honor_dmarc_policy - ): + if defender_client.antiphishing_policies: + # Only Default Defender Anti-Phishing Policy exists since there are only anti phishing rules when there are custom policies + if not defender_client.antiphishing_rules: + # Get the only policy in the dictionary since there is only the default policy + policy = next(iter(defender_client.antiphishing_policies.values())) + + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.name, + resource_id=policy.name, + ) + + if self._is_policy_properly_configured(policy): + # Case 1: Default policy exists and is properly configured report.status = "PASS" - report.status_extended = f"Anti-phishing policy {policy_name} is properly configured and enabled." + report.status_extended = f"{policy.name} is the only policy and it's properly configured in the default Defender Anti-Phishing Policy." + else: + # Case 5: Default policy exists but is not properly configured + report.status = "FAIL" + report.status_extended = f"{policy.name} is the only policy and it's not properly configured in the default Defender Anti-Phishing Policy." + findings.append(report) - findings.append(report) + # Multiple Defender Anti-Phishing Policies + else: + default_policy_well_configured = False + + for ( + policy_name, + policy, + ) in defender_client.antiphishing_policies.items(): + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy_name, + resource_id=policy_name, + ) + if policy.default: + if not self._is_policy_properly_configured(policy): + # Case 4: Default policy is not properly configured and there are other policies + report.status = "FAIL" + report.status_extended = f"{policy_name} is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy." + findings.append(report) + else: + # Case 2: Default policy is properly configured and there are other policies + report.status = "PASS" + report.status_extended = f"{policy_name} is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy." + default_policy_well_configured = True + findings.append(report) + else: + if not self._is_policy_properly_configured(policy): + included_resources = [] + + if defender_client.antiphishing_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.antiphishing_rules[policy.name].users)}" + ) + if defender_client.antiphishing_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.antiphishing_rules[policy.name].groups)}" + ) + if defender_client.antiphishing_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.antiphishing_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + # Case 3: Default policy is properly configured but other custom policies are not + if default_policy_well_configured: + report.status = "FAIL" + report.status_extended = ( + f"Custom Anti-phishing policy {policy_name} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). " + "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + # Case 5: Default policy is not properly configured and other custom policies are not + else: + report.status = "FAIL" + report.status_extended = ( + f"Custom Anti-phishing policy {policy_name} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.antiphishing_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.antiphishing_rules[policy.name].users)}" + ) + if defender_client.antiphishing_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.antiphishing_rules[policy.name].groups)}" + ) + if defender_client.antiphishing_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.antiphishing_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + # Case 2: Default policy is properly configured and other custom policies are too + if default_policy_well_configured: + report.status = "PASS" + report.status_extended = ( + f"Custom Anti-phishing policy {policy_name} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + + # Case 6: Default policy is not properly configured but other custom policies are + else: + report.status = "PASS" + report.status_extended = ( + f"Custom Anti-phishing policy {policy_name} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). " + "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _is_policy_properly_configured(self, policy) -> bool: + """ + Check if a policy is properly configured according to best practices. + + Args: + policy: The anti-phishing policy to check. + + Returns: + bool: True if the policy is properly configured, False otherwise. + """ + return ( + ( + policy.default + or defender_client.antiphishing_rules[policy.name].state.lower() + == "enabled" + ) + and policy.spoof_intelligence + and policy.spoof_intelligence_action.lower() == "quarantine" + and policy.dmarc_reject_action.lower() == "quarantine" + and policy.dmarc_quarantine_action.lower() == "quarantine" + and policy.safety_tips + and policy.unauthenticated_sender_action + and policy.show_tag + and policy.honor_dmarc_policy + ) diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py index b4a0f2e31b..cd1eafdabf 100644 --- a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py +++ b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured.py @@ -6,8 +6,7 @@ from prowler.providers.m365.services.defender.defender_client import defender_cl class defender_antispam_outbound_policy_configured(Check): """ - Check if the Exchange Online Spam Policies are configured to notify administrators - when a sender is blocked for sending spam emails. + Check if the outbound spam policy is established and properly configured in the Defender service. Attributes: metadata: Metadata associated with the check (inherited from Check). @@ -15,40 +14,159 @@ class defender_antispam_outbound_policy_configured(Check): def execute(self) -> List[CheckReportM365]: """ - Execute the check to verify if the Exchange Online Spam Policies notify administrators - when a sender is blocked for sending spam emails. + Execute the check to verify if an outbound spam policy is established and properly configured. + + This method checks the Defender outbound spam policies to ensure they are configured + according to best practices. Returns: List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - for policy_name, policy in defender_client.outbound_spam_policies.items(): - report = CheckReportM365( - metadata=self.metadata(), - resource=policy, - resource_name="Defender Outbound Spam Policy", - resource_id=policy_name, - ) - report.status = "FAIL" - report.status_extended = ( - f"Outbound Spam Policy {policy_name} is not properly configured." - ) - if ( - not policy.default - and policy_name in defender_client.outbound_spam_rules - and defender_client.outbound_spam_rules[policy_name].state.lower() - == "enabled" - ) or policy.default: - if ( - policy.notify_limit_exceeded - and policy.notify_sender_blocked - and policy.notify_limit_exceeded_addresses - and policy.notify_sender_blocked_addresses - ): + if defender_client.outbound_spam_policies: + # Only Default Defender Outbound Spam Policy + if not defender_client.outbound_spam_rules: + # Get the only policy in the dictionary + policy = next(iter(defender_client.outbound_spam_policies.values())) + + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.name, + resource_id=policy.name, + ) + + if self._is_policy_properly_configured(policy): + # Case 1: Default policy exists and is properly configured report.status = "PASS" - report.status_extended = f"Outbound Spam Policy {policy_name} is properly configured and enabled." + report.status_extended = f"{policy.name} is the only policy and it's properly configured in the default Defender Outbound Spam Policy." + else: + # Case 5: Default policy exists but is not properly configured + report.status = "FAIL" + report.status_extended = f"{policy.name} is the only policy and it's not properly configured in the default Defender Outbound Spam Policy." + findings.append(report) - findings.append(report) + # Multiple Defender Outbound Spam Policies + else: + default_policy_well_configured = False + + for ( + policy_name, + policy, + ) in defender_client.outbound_spam_policies.items(): + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy_name, + resource_id=policy_name, + ) + if policy.default: + if not self._is_policy_properly_configured(policy): + # Case 4: Default policy is not properly configured and there are other policies + report.status = "FAIL" + report.status_extended = f"{policy_name} is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy." + findings.append(report) + else: + # Case 2: Default policy is properly configured and there are other policies + report.status = "PASS" + report.status_extended = f"{policy_name} is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy." + default_policy_well_configured = True + findings.append(report) + else: + if not self._is_policy_properly_configured(policy): + included_resources = [] + + if defender_client.outbound_spam_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}" + ) + if defender_client.outbound_spam_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}" + ) + if defender_client.outbound_spam_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + # Case 3: Default policy is properly configured but other custom policies are not + if default_policy_well_configured: + report.status = "FAIL" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + # Case 5: Default policy is not properly configured and other custom policies are not + else: + report.status = "FAIL" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.outbound_spam_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}" + ) + if defender_client.outbound_spam_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}" + ) + if defender_client.outbound_spam_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + # Case 2: Default policy is properly configured and other custom policies are too + if default_policy_well_configured: + report.status = "PASS" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + # Case 6: Default policy is not properly configured but other custom policies are + else: + report.status = "PASS" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _is_policy_properly_configured(self, policy) -> bool: + """ + Check if a policy is properly configured according to best practices. + + Args: + policy: The outbound spam policy to check. + + Returns: + bool: True if the policy is properly configured, False otherwise. + """ + return ( + ( + policy.default + or defender_client.outbound_spam_rules[policy.name].state.lower() + == "enabled" + ) + and policy.notify_limit_exceeded + and policy.notify_sender_blocked + and policy.notify_limit_exceeded_addresses + and policy.notify_sender_blocked_addresses + ) diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py index 8bb8c4fa60..04f81f62b3 100644 --- a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py +++ b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py @@ -20,28 +20,150 @@ class defender_antispam_outbound_policy_forwarding_disabled(Check): List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - for policy_name, policy in defender_client.outbound_spam_policies.items(): - report = CheckReportM365( - metadata=self.metadata(), - resource=policy, - resource_name="Defender Outbound Spam Policy", - resource_id=policy_name, - ) - report.status = "FAIL" - report.status_extended = ( - f"Outbound Spam Policy {policy_name} does allow mail forwarding." - ) - if ( - not policy.default - and policy_name in defender_client.outbound_spam_rules - and defender_client.outbound_spam_rules[policy_name].state.lower() - == "enabled" - ) or policy.default: - if not policy.auto_forwarding_mode: + if defender_client.outbound_spam_policies: + # Only Default Defender Outbound Spam Policy exists + if not defender_client.outbound_spam_rules: + policy = next(iter(defender_client.outbound_spam_policies.values())) + + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.name, + resource_id=policy.name, + ) + + if self._is_forwarding_disabled(policy): + # Case 1: Default policy exists and has forwarding disabled report.status = "PASS" - report.status_extended = f"Outbound Spam Policy {policy_name} does not allow mail forwarding." + report.status_extended = f"{policy.name} is the only policy and mail forwarding is disabled." + else: + # Case 5: Default policy exists but allows forwarding + report.status = "FAIL" + report.status_extended = f"{policy.name} is the only policy and mail forwarding is allowed." + findings.append(report) - findings.append(report) + # Multiple Defender Outbound Spam Policies exist + else: + default_policy_well_configured = False + + for ( + policy_name, + policy, + ) in defender_client.outbound_spam_policies.items(): + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy_name, + resource_id=policy_name, + ) + + if policy.default: + if not self._is_forwarding_disabled(policy): + # Case 4: Default policy allows forwarding and there are other policies + report.status = "FAIL" + report.status_extended = ( + f"{policy_name} is the default policy and mail forwarding is allowed, " + "but it could be overridden by another well-configured Custom Policy." + ) + findings.append(report) + else: + # Case 2: Default policy disables forwarding and there are other policies + report.status = "PASS" + report.status_extended = ( + f"{policy_name} is the default policy and mail forwarding is disabled, " + "but it could be overridden by another misconfigured Custom Policy." + ) + default_policy_well_configured = True + findings.append(report) + else: + if not self._is_forwarding_disabled(policy): + included_resources = [] + + if defender_client.outbound_spam_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}" + ) + if defender_client.outbound_spam_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}" + ) + if defender_client.outbound_spam_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 3: Default policy disables forwarding but custom one doesn't + report.status = "FAIL" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "However, the default policy disables mail forwarding, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + else: + # Case 5: Neither default nor custom policies disable forwarding + report.status = "FAIL" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.outbound_spam_rules[policy.name].users: + included_resources.append( + f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}" + ) + if defender_client.outbound_spam_rules[policy.name].groups: + included_resources.append( + f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}" + ) + if defender_client.outbound_spam_rules[policy.name].domains: + included_resources.append( + f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 2: Both default and custom policies disable forwarding + report.status = "PASS" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "Also, the default policy disables mail forwarding, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + else: + # Case 6: Default policy allows forwarding, custom policy disables it + report.status = "PASS" + report.status_extended = ( + f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, " + f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). " + "However, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _is_forwarding_disabled(self, policy) -> bool: + """ + Check if mail forwarding is disabled in the policy. + + Args: + policy: The outbound spam policy to check. + + Returns: + bool: True if mail forwarding is disabled, False otherwise. + """ + return ( + policy.default + or defender_client.outbound_spam_rules[policy.name].state.lower() + == "enabled" + ) and not policy.auto_forwarding_mode diff --git a/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py index 71dbb7e45f..67b6643e9e 100644 --- a/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py +++ b/prowler/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains.py @@ -23,20 +23,163 @@ class defender_antispam_policy_inbound_no_allowed_domains(Check): List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - for policy in defender_client.inbound_spam_policies: - report = CheckReportM365( - metadata=self.metadata(), - resource=policy, - resource_name="Defender Inbound Spam Policy", - resource_id=policy.identity, - ) - report.status = "PASS" - report.status_extended = f"Inbound anti-spam policy {policy.identity} does not contain allowed domains." - if policy.allowed_sender_domains: - report.status = "FAIL" - report.status_extended = f"Inbound anti-spam policy {policy.identity} contains allowed domains: {policy.allowed_sender_domains}." + if defender_client.inbound_spam_policies: + # Only Default Defender Inbound Spam Policy exists + if not defender_client.inbound_spam_rules: + policy = defender_client.inbound_spam_policies[0] - findings.append(report) + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.identity, + resource_id=policy.identity, + ) + + if self._has_no_allowed_domains(policy): + # Case 1: Default policy exists and has no allowed domains + report.status = "PASS" + report.status_extended = f"{policy.identity} is the only policy and it does not contain allowed domains." + else: + # Case 5: Default policy exists but contains allowed domains + report.status = "FAIL" + report.status_extended = f"{policy.identity} is the only policy and it contains allowed domains: {', '.join(policy.allowed_sender_domains)}." + findings.append(report) + + # Multiple Defender Inbound Spam Policies exist + else: + default_policy_well_configured = False + + for policy in defender_client.inbound_spam_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.identity, + resource_id=policy.identity, + ) + + if policy.default: + if not self._has_no_allowed_domains(policy): + # Case 4: Default policy contains allowed domains + report.status = "FAIL" + report.status_extended = ( + f"{policy.identity} is the default policy and it contains allowed domains: {', '.join(policy.allowed_sender_domains)}, " + "but it could be overridden by another well-configured Custom Policy." + ) + findings.append(report) + else: + # Case 2: Default policy has no allowed domains and there are other policies + report.status = "PASS" + report.status_extended = ( + f"{policy.identity} is the default policy and it does not contain allowed domains, " + "but it could be overridden by another misconfigured Custom Policy." + ) + default_policy_well_configured = True + findings.append(report) + else: + if not self._has_no_allowed_domains(policy): + included_resources = [] + + if defender_client.inbound_spam_rules[ + policy.identity + ].users: + included_resources.append( + f"users: {', '.join(defender_client.inbound_spam_rules[policy.identity].users)}" + ) + if defender_client.inbound_spam_rules[ + policy.identity + ].groups: + included_resources.append( + f"groups: {', '.join(defender_client.inbound_spam_rules[policy.identity].groups)}" + ) + if defender_client.inbound_spam_rules[ + policy.identity + ].domains: + included_resources.append( + f"domains: {', '.join(defender_client.inbound_spam_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + priority = defender_client.inbound_spam_rules[ + policy.identity + ].priority + + if default_policy_well_configured: + # Case 3: Default policy has no allowed domains but custom one does + report.status = "FAIL" + report.status_extended = ( + f"Custom Inbound Spam policy {policy.identity} contains allowed domains and includes {included_resources_str}, " + f"with priority {priority} (0 is the highest). However, the default policy does not contain allowed domains, " + "so entities not included by this custom policy could be correctly protected." + ) + else: + # Case 5: Neither default nor custom policies are correctly configured + report.status = "FAIL" + report.status_extended = ( + f"Custom Inbound Spam policy {policy.identity} contains allowed domains and includes {included_resources_str}, " + f"with priority {priority} (0 is the highest). Also, the default policy contains allowed domains, " + "so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.inbound_spam_rules[ + policy.identity + ].users: + included_resources.append( + f"users: {', '.join(defender_client.inbound_spam_rules[policy.identity].users)}" + ) + if defender_client.inbound_spam_rules[ + policy.identity + ].groups: + included_resources.append( + f"groups: {', '.join(defender_client.inbound_spam_rules[policy.identity].groups)}" + ) + if defender_client.inbound_spam_rules[ + policy.identity + ].domains: + included_resources.append( + f"domains: {', '.join(defender_client.inbound_spam_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + priority = defender_client.inbound_spam_rules[ + policy.identity + ].priority + + if default_policy_well_configured: + # Case 2: Both default and custom policies do not contain allowed domains + report.status = "PASS" + report.status_extended = ( + f"Custom Inbound Spam policy {policy.identity} does not contain allowed domains and includes {included_resources_str}, " + f"with priority {priority} (0 is the highest). Also, the default policy does not contain allowed domains, " + "so entities not included by this custom policy could still be correctly protected." + ) + else: + # Case 6: Default policy contains allowed domains, custom policy does not + report.status = "PASS" + report.status_extended = ( + f"Custom Inbound Spam policy {policy.identity} does not contain allowed domains and includes {included_resources_str}, " + f"with priority {priority} (0 is the highest). However, the default policy contains allowed domains, " + "so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _has_no_allowed_domains(self, policy) -> bool: + """ + Check if the policy has no allowed domains. + + Args: + policy: The inbound spam policy to check. + + Returns: + bool: True if the policy has no allowed domains, False otherwise. + """ + return ( + policy.default + or defender_client.inbound_spam_rules[policy.identity].state.lower() + == "enabled" + ) and not policy.allowed_sender_domains diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py index 75c9707d26..a0b817cda3 100644 --- a/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py +++ b/prowler/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled.py @@ -16,39 +16,138 @@ class defender_malware_policy_common_attachments_filter_enabled(Check): """ Execute the check to verify if the Common Attachment Types Filter is enabled. - This method checks the Defender anti-malware policy to determine if the + This method checks the Defender anti-malware policies to determine if the Common Attachment Types Filter is enabled. Returns: List[CheckReportM365]: A list of reports containing the result of the check. """ findings = [] - if not defender_client.malware_policies: - report = CheckReportM365( - metadata=self.metadata(), - resource={}, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", - ) - report.status = "FAIL" - report.status_extended = "Common Attachment Types Filter is not enabled." - findings.append(report) - else: - for policy in defender_client.malware_policies: + + if defender_client.malware_policies: + # Only Default Defender Malware Policy exists + if not defender_client.malware_rules: + policy = defender_client.malware_policies[0] + report = CheckReportM365( metadata=self.metadata(), resource=policy, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", + resource_name=policy.identity, + resource_id=policy.identity, ) - report.status = "FAIL" - report.status_extended = f"Common Attachment Types Filter is not enabled in anti-malware policy {policy.identity}." if policy.enable_file_filter: + # Case 1: Default policy exists and has the setting enabled report.status = "PASS" - report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}." - break + report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is enabled." + else: + # Case 5: Default policy exists but doesn't have the setting enabled + report.status = "FAIL" + report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is not enabled." + findings.append(report) - findings.append(report) + # Multiple Defender Malware Policies exist + else: + default_policy_well_configured = False + + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.identity, + resource_id=policy.identity, + ) + + if policy.is_default: + if not policy.enable_file_filter: + # Case 4: Default policy doesn't have the setting enabled and there are other policies + report.status = "FAIL" + report.status_extended = ( + f"{policy.identity} is the default policy and Common Attachment Types Filter is not enabled, " + "but it could be overridden by another well-configured Custom Policy." + ) + findings.append(report) + else: + # Case 2: Default policy has the setting enabled and there are other policies + report.status = "PASS" + report.status_extended = ( + f"{policy.identity} is the default policy and Common Attachment Types Filter is enabled, " + "but it could be overridden by another misconfigured Custom Policy." + ) + default_policy_well_configured = True + findings.append(report) + else: + if not policy.enable_file_filter: + included_resources = [] + + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 3: Default policy enables the setting but custom one doesn't + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} does not enable Common Attachment Types Filter and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "However, the default policy enables the filter, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + else: + # Case 5: Neither default nor custom policies enable the setting + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} does not enable Common Attachment Types Filter and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "Also, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 2: Both default and custom policies enable the setting + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} enables Common Attachment Types Filter and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "Also, the default policy enables the filter, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + else: + # Case 6: Default policy doesn't enable the setting, but custom policy does + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} enables Common Attachment Types Filter and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "However, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied.py b/prowler/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied.py index cd2682d538..87aa4ab50e 100644 --- a/prowler/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied.py +++ b/prowler/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied.py @@ -14,17 +14,16 @@ class defender_malware_policy_comprehensive_attachments_filter_applied(Check): def execute(self) -> List[CheckReportM365]: """ - Executes the check to determine if the Common Attachment Types Filter is enabled. + Executes the check to determine if the Common Attachment Types Filter is properly configured. - This method evaluates the Defender anti-malware policy to ensure it is enabled and the - Common Attachment Types Filter is active and applied to the recommended file types. + This method evaluates the Defender anti-malware policies to ensure the filter is enabled and applied + to all recommended file types. Returns: List[CheckReportM365]: A list of reports with the results of the check. """ findings = [] - # Default to Microsoft-recommended common file types default_recommended_extensions = [ "ace", "ani", @@ -81,63 +80,175 @@ class defender_malware_policy_comprehensive_attachments_filter_applied(Check): "z", ] - # Load extensions from audit_config (user config), fallback to default recommended_extensions = defender_client.audit_config.get( "recommended_blocked_file_types", default_recommended_extensions ) - if not defender_client.malware_policies: - report = CheckReportM365( - metadata=self.metadata(), - resource={}, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", - ) - report.status = "FAIL" - report.status_extended = "Common Attachment Types Filter is not enabled." - findings.append(report) - else: - for policy in defender_client.malware_policies: + if defender_client.malware_policies: + # Only Default Defender Malware Policy exists + if not defender_client.malware_rules: + policy = defender_client.malware_policies[0] + report = CheckReportM365( metadata=self.metadata(), resource=policy, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", + resource_name=policy.identity, + resource_id=policy.identity, ) - report.status = "FAIL" - report.status_extended = f"Common Attachment Types Filter is not properly configured in anti-malware policy {policy.identity}." - if not policy.enable_file_filter: - report.status_extended = f"Common Attachment Types Filter is not enabled in anti-malware policy {policy.identity}." - break + if self._is_filter_properly_configured(policy, recommended_extensions): + # Case 1: Default policy exists and has filter properly configured + report.status = "PASS" + report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is properly configured." + else: + # Case 5: Default policy exists but doesn't have filter properly configured + missing = self._get_missing_extensions( + policy, recommended_extensions + ) + report.status = "FAIL" + report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is not properly configured. Missing recommended file types: {', '.join(missing)}." + findings.append(report) - if ( - not policy.is_default - and policy.identity in defender_client.malware_rules - ) or policy.is_default: - if ( - not policy.is_default - and defender_client.malware_rules[policy.identity].state.lower() - == "enabled" - ) or policy.is_default: - blocked_extensions = [ext.lower() for ext in policy.file_types] - missing = [ - ext - for ext in recommended_extensions - if ext.lower() not in blocked_extensions - ] + # Multiple Defender Malware Policies exist + else: + default_policy_well_configured = False - if missing: - report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, but the following recommended file types are missing: {', '.join(missing)}." - break - - report.status = "PASS" - report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, the policy is enabled and the filter is applied to the recommended file types." + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.identity, + resource_id=policy.identity, + ) + if policy.is_default: + if not self._is_filter_properly_configured( + policy, recommended_extensions + ): + # Case 4: Default policy is not properly configured + missing = self._get_missing_extensions( + policy, recommended_extensions + ) + report.status = "FAIL" + report.status_extended = ( + f"{policy.identity} is the default policy and Common Attachment Types Filter is not properly configured, " + f"but it could be overridden by another well-configured Custom Policy. Missing recommended file types: {', '.join(missing)}." + ) + findings.append(report) + else: + # Case 2: Default policy is properly configured + report.status = "PASS" + report.status_extended = ( + f"{policy.identity} is the default policy and Common Attachment Types Filter is properly configured, " + "but it could be overridden by another misconfigured Custom Policy." + ) + default_policy_well_configured = True + findings.append(report) else: - report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, but the policy is disabled." - break + if not self._is_filter_properly_configured( + policy, recommended_extensions + ): + included_resources = [] - findings.append(report) + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + missing = self._get_missing_extensions( + policy, recommended_extensions + ) + + if default_policy_well_configured: + # Case 3: Default policy is configured, custom one isn't + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + f"Missing recommended file types: {', '.join(missing)}. " + "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + else: + # Case 5: Neither default nor custom policy is properly configured + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + f"Missing recommended file types: {', '.join(missing)}. " + "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 2: Both default and custom policies are properly configured + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + else: + # Case 6: Default policy not configured, custom policy is + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _is_filter_properly_configured(self, policy, recommended_extensions) -> bool: + if not policy.enable_file_filter: + return False + + if ( + not policy.is_default + and policy.identity in defender_client.malware_rules + and defender_client.malware_rules[policy.identity].state.lower() + != "enabled" + ): + return False + + blocked_extensions = [ext.lower() for ext in policy.file_types] + return all(ext.lower() in blocked_extensions for ext in recommended_extensions) + + def _get_missing_extensions(self, policy, recommended_extensions) -> List[str]: + if not policy.enable_file_filter: + return recommended_extensions + + blocked_extensions = [ext.lower() for ext in policy.file_types] + return [ + ext + for ext in recommended_extensions + if ext.lower() not in blocked_extensions + ] diff --git a/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py index 6eaf933c6a..735cc6b9e9 100644 --- a/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py +++ b/prowler/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled.py @@ -16,47 +16,152 @@ class defender_malware_policy_notifications_internal_users_malware_enabled(Check """ Execute the check to verify if notifications for internal users sending malware are enabled. - This method checks the Defender anti-malware policy to determine if notifications for internal users - sending malware are enabled. + This method evaluates the Defender anti-malware policies to ensure internal sender notifications + are properly configured. Returns: - List[CheckReportM365]: A list of reports containing the result of the check. + List[CheckReportM365]: A list of reports with the results of the check. """ findings = [] - if not defender_client.malware_policies: - report = CheckReportM365( - metadata=self.metadata(), - resource={}, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", - ) - report.status = "FAIL" - report.status_extended = ( - "Notifications for internal users sending malware are not enabled." - ) - findings.append(report) - else: - for policy in defender_client.malware_policies: + + if defender_client.malware_policies: + # Only Default Defender Malware Policy exists + if not defender_client.malware_rules: + policy = defender_client.malware_policies[0] + report = CheckReportM365( metadata=self.metadata(), resource=policy, - resource_name="Defender Malware Policy", - resource_id="defenderMalwarePolicy", - ) - report.status = "FAIL" - report.status_extended = ( - "Notifications for internal users sending malware are not enabled." + resource_name=policy.identity, + resource_id=policy.identity, ) - if policy.enable_internal_sender_admin_notifications: - if policy.internal_sender_admin_address: - report.status = "PASS" - report.status_extended = "Notifications for internal users sending malware are enabled." - break + if self._are_notifications_enabled(policy): + # Case 1: Default policy exists and has notifications enabled + report.status = "PASS" + report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are enabled." + else: + # Case 5: Default policy exists but doesn't have notifications enabled + report.status = "FAIL" + report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are not enabled." + findings.append(report) + + # Multiple Defender Malware Policies exist + else: + default_policy_well_configured = False + + for policy in defender_client.malware_policies: + report = CheckReportM365( + metadata=self.metadata(), + resource=policy, + resource_name=policy.identity, + resource_id=policy.identity, + ) + + if policy.is_default: + if not self._are_notifications_enabled(policy): + # Case 4: Default policy not configured + report.status = "FAIL" + report.status_extended = ( + f"{policy.identity} is the default policy and notifications for internal users sending malware are not enabled, " + "but it could be overridden by another well-configured Custom Policy." + ) + findings.append(report) + else: + # Case 2: Default policy is properly configured + report.status = "PASS" + report.status_extended = ( + f"{policy.identity} is the default policy and notifications for internal users sending malware are enabled, " + "but it could be overridden by another misconfigured Custom Policy." + ) + default_policy_well_configured = True + findings.append(report) else: - report.status = "FAIL" - report.status_extended = "Notifications for internal users sending malware are enabled, but no email addresses are configured." + if not self._are_notifications_enabled(policy): + included_resources = [] - findings.append(report) + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 3: Default policy is configured, custom one isn't + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + findings.append(report) + else: + # Case 5: Neither default nor custom policy is properly configured + report.status = "FAIL" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) + else: + included_resources = [] + + if defender_client.malware_rules[policy.identity].users: + included_resources.append( + f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}" + ) + if defender_client.malware_rules[policy.identity].groups: + included_resources.append( + f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}" + ) + if defender_client.malware_rules[policy.identity].domains: + included_resources.append( + f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}" + ) + + included_resources_str = "; ".join(included_resources) + + if default_policy_well_configured: + # Case 2: Both default and custom policies are properly configured + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + findings.append(report) + else: + # Case 6: Default policy not configured, custom policy is + report.status = "PASS" + report.status_extended = ( + f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, " + f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). " + "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + findings.append(report) return findings + + def _are_notifications_enabled(self, policy) -> bool: + if ( + not policy.is_default + and policy.identity in defender_client.malware_rules + and defender_client.malware_rules[policy.identity].state.lower() + != "enabled" + ): + return False + + return ( + policy.enable_internal_sender_admin_notifications + and policy.internal_sender_admin_address + ) diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index cec2e7dce4..9ea4a64afd 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from pydantic import BaseModel @@ -14,10 +14,11 @@ class Defender(M365Service): self.outbound_spam_policies = {} self.outbound_spam_rules = {} self.antiphishing_policies = {} - self.antiphising_rules = {} + self.antiphishing_rules = {} self.connection_filter_policy = None self.dkim_configurations = [] self.inbound_spam_policies = [] + self.inbound_spam_rules = {} self.report_submission_policy = None if self.powershell: self.powershell.connect_exchange_online() @@ -25,11 +26,12 @@ class Defender(M365Service): self.malware_rules = self._get_malware_filter_rule() self.outbound_spam_policies = self._get_outbound_spam_filter_policy() self.outbound_spam_rules = self._get_outbound_spam_filter_rule() - self.antiphishing_policies = self._get_antiphising_policy() - self.antiphising_rules = self._get_antiphising_rules() + self.antiphishing_policies = self._get_antiphishing_policy() + self.antiphishing_rules = self._get_antiphishing_rules() self.connection_filter_policy = self._get_connection_filter_policy() self.dkim_configurations = self._get_dkim_config() self.inbound_spam_policies = self._get_inbound_spam_filter_policy() + self.inbound_spam_rules = self._get_inbound_spam_filter_rule() self.report_submission_policy = self._get_report_submission_policy() self.powershell.close() @@ -44,7 +46,7 @@ class Defender(M365Service): if policy: malware_policies.append( MalwarePolicy( - enable_file_filter=policy.get("EnableFileFilter", True), + enable_file_filter=policy.get("EnableFileFilter", False), identity=policy.get("Identity", ""), enable_internal_sender_admin_notifications=policy.get( "EnableInternalSenderAdminNotifications", False @@ -56,6 +58,7 @@ class Defender(M365Service): is_default=policy.get("IsDefault", False), ) ) + malware_policies.sort(key=lambda x: x.is_default, reverse=True) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -73,6 +76,10 @@ class Defender(M365Service): if rule: malware_rules[rule.get("Name", "")] = MalwareRule( state=rule.get("State", ""), + priority=rule.get("Priority", 0), + users=rule.get("SentTo", None), + groups=rule.get("SentToMemberOf", None), + domains=rule.get("RecipientDomainIs", None), ) except Exception as error: logger.error( @@ -80,7 +87,7 @@ class Defender(M365Service): ) return malware_rules - def _get_antiphising_policy(self): + def _get_antiphishing_policy(self): logger.info("Microsoft365 - Getting Defender antiphishing policy...") antiphishing_policies = {} try: @@ -90,6 +97,7 @@ class Defender(M365Service): for policy in antiphishing_policy: if policy: antiphishing_policies[policy.get("Name", "")] = AntiphishingPolicy( + name=policy.get("Name", ""), spoof_intelligence=policy.get("EnableSpoofIntelligence", True), spoof_intelligence_action=policy.get( "AuthenticationFailAction", "" @@ -104,13 +112,21 @@ class Defender(M365Service): honor_dmarc_policy=policy.get("HonorDmarcPolicy", True), default=policy.get("IsDefault", False), ) + + antiphishing_policies = dict( + sorted( + antiphishing_policies.items(), + key=lambda item: item[1].default, + reverse=True, + ) + ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) return antiphishing_policies - def _get_antiphising_rules(self): + def _get_antiphishing_rules(self): logger.info("Microsoft365 - Getting Defender antiphishing rules...") antiphishing_rules = {} try: @@ -121,6 +137,10 @@ class Defender(M365Service): if rule: antiphishing_rules[rule.get("Name", "")] = AntiphishingRule( state=rule.get("State", ""), + priority=rule.get("Priority", 0), + users=rule.get("SentTo", None), + groups=rule.get("SentToMemberOf", None), + domains=rule.get("RecipientDomainIs", None), ) except Exception as error: logger.error( @@ -176,6 +196,7 @@ class Defender(M365Service): for policy in outbound_spam_policy: if policy: outbound_spam_policies[policy.get("Name", "")] = OutboundSpamPolicy( + name=policy.get("Name", ""), notify_sender_blocked=policy.get("NotifyOutboundSpam", True), notify_limit_exceeded=policy.get( "BccSuspiciousOutboundMail", True @@ -189,6 +210,14 @@ class Defender(M365Service): auto_forwarding_mode=policy.get("AutoForwardingMode", True), default=policy.get("IsDefault", False), ) + + outbound_spam_policies = dict( + sorted( + outbound_spam_policies.items(), + key=lambda item: item[1].default, + reverse=True, + ) + ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -206,6 +235,10 @@ class Defender(M365Service): if rule: outbound_spam_rules[rule.get("Name", "")] = OutboundSpamRule( state=rule.get("State", "Disabled"), + priority=rule.get("Priority", 0), + users=rule.get("From", None), + groups=rule.get("FromMemberOf", None), + domains=rule.get("SenderDomainIs", None), ) except Exception as error: logger.error( @@ -230,14 +263,38 @@ class Defender(M365Service): allowed_sender_domains=policy.get( "AllowedSenderDomains", [] ), + default=policy.get("IsDefault", False), ) ) + inbound_spam_policies.sort(key=lambda x: x.default, reverse=True) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) return inbound_spam_policies + def _get_inbound_spam_filter_rule(self): + logger.info("Microsoft365 - Getting Defender inbound spam filter rule...") + inbound_spam_rules = {} + try: + inbound_spam_rule = self.powershell.get_inbound_spam_filter_rule() + if isinstance(inbound_spam_rule, dict): + inbound_spam_rule = [inbound_spam_rule] + for rule in inbound_spam_rule: + if rule: + inbound_spam_rules[rule.get("Name", "")] = InboundSpamRule( + state=rule.get("State", "Disabled"), + priority=rule.get("Priority", 0), + users=rule.get("SentTo", None), + groups=rule.get("SentToMemberOf", None), + domains=rule.get("RecipientDomainIs", None), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return inbound_spam_rules + def _get_report_submission_policy(self): logger.info("Microsoft365 - Getting Defender report submission policy...") report_submission_policy = None @@ -288,9 +345,14 @@ class MalwarePolicy(BaseModel): class MalwareRule(BaseModel): state: str + priority: int + users: Optional[list[str]] + groups: Optional[list[str]] + domains: Optional[list[str]] class AntiphishingPolicy(BaseModel): + name: str spoof_intelligence: bool spoof_intelligence_action: str dmarc_reject_action: str @@ -304,6 +366,10 @@ class AntiphishingPolicy(BaseModel): class AntiphishingRule(BaseModel): state: str + priority: int + users: Optional[list[str]] + groups: Optional[list[str]] + domains: Optional[list[str]] class ConnectionFilterPolicy(BaseModel): @@ -318,6 +384,7 @@ class DkimConfig(BaseModel): class OutboundSpamPolicy(BaseModel): + name: str notify_sender_blocked: bool notify_limit_exceeded: bool notify_limit_exceeded_addresses: List[str] @@ -328,11 +395,24 @@ class OutboundSpamPolicy(BaseModel): class OutboundSpamRule(BaseModel): state: str + priority: int + users: Optional[list[str]] + groups: Optional[list[str]] + domains: Optional[list[str]] class DefenderInboundSpamPolicy(BaseModel): identity: str allowed_sender_domains: list[str] = [] + default: bool + + +class InboundSpamRule(BaseModel): + state: str + priority: int + users: Optional[list[str]] + groups: Optional[list[str]] + domains: Optional[list[str]] class ReportSubmissionPolicy(BaseModel): diff --git a/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py b/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py index b460646dae..8610e96769 100644 --- a/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py +++ b/tests/providers/m365/services/defender/defender_antiphishing_policy_configured/defender_antiphishing_policy_configured_test.py @@ -4,7 +4,69 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_antiphishing_policy_configured: - def test_properly_configured_custom_policy(self): + def test_case_1_default_policy_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + ) + + defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + name="Default", + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=True, + ) + } + defender_client.antiphishing_rules = {} + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the only policy and it's properly configured in the default Defender Anti-Phishing Policy." + ) + assert ( + result[0].resource_name + == defender_client.antiphishing_policies["Default"].name + ) + assert ( + result[0].resource_id + == defender_client.antiphishing_policies["Default"].name + ) + assert ( + result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + + def test_case_2_all_policies_properly_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -31,7 +93,20 @@ class Test_defender_antiphishing_policy_configured: ) defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + name="Default", + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=True, + ), "Policy1": AntiphishingPolicy( + name="Policy1", spoof_intelligence=True, spoof_intelligence_action="Quarantine", dmarc_reject_action="Quarantine", @@ -41,29 +116,59 @@ class Test_defender_antiphishing_policy_configured: show_tag=True, honor_dmarc_policy=True, default=False, - ) + ), } - defender_client.antiphising_rules = { - "Policy1": AntiphishingRule(state="Enabled") + defender_client.antiphishing_rules = { + "Policy1": AntiphishingRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ) } check = defender_antiphishing_policy_configured() result = check.execute() - assert len(result) == 1 + assert len(result) == 2 assert result[0].status == "PASS" assert ( result[0].status_extended - == "Anti-phishing policy Policy1 is properly configured and enabled." + == "Default is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy." + ) + assert ( + result[0].resource_name + == defender_client.antiphishing_policies["Default"].name + ) + assert ( + result[0].resource_id + == defender_client.antiphishing_policies["Default"].name ) assert ( result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == f"Custom Anti-phishing policy {defender_client.antiphishing_policies['Policy1'].name} is properly configured and includes users: {', '.join(defender_client.antiphishing_rules['Policy1'].users)}; groups: {', '.join(defender_client.antiphishing_rules['Policy1'].groups)}; domains: {', '.join(defender_client.antiphishing_rules['Policy1'].domains)}, " + f"with priority {defender_client.antiphishing_rules['Policy1'].priority} (0 is the highest). " + "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + assert ( + result[1].resource_name + == defender_client.antiphishing_policies["Policy1"].name + ) + assert ( + result[1].resource_id + == defender_client.antiphishing_policies["Policy1"].name + ) + assert ( + result[1].resource == defender_client.antiphishing_policies["Policy1"].dict() ) - assert result[0].resource_name == "Defender Anti-Phishing Policy" - assert result[0].resource_id == "Policy1" - assert result[0].location == "global" - def test_not_properly_configured_policy(self): + def test_case_3_default_ok_others_not(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -89,66 +194,9 @@ class Test_defender_antiphishing_policy_configured: AntiphishingRule, ) - defender_client.antiphishing_policies = { - "Policy2": AntiphishingPolicy( - spoof_intelligence=False, - spoof_intelligence_action="None", - dmarc_reject_action="None", - dmarc_quarantine_action="None", - safety_tips=False, - unauthenticated_sender_action=False, - show_tag=False, - honor_dmarc_policy=False, - default=False, - ) - } - defender_client.antiphising_rules = { - "Policy2": AntiphishingRule(state="Enabled") - } - - check = defender_antiphishing_policy_configured() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Anti-phishing policy Policy2 is not properly configured." - ) - assert ( - result[0].resource - == defender_client.antiphishing_policies["Policy2"].dict() - ) - assert result[0].resource_name == "Defender Anti-Phishing Policy" - assert result[0].resource_id == "Policy2" - assert result[0].location == "global" - - def test_properly_configured_default_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( - defender_antiphishing_policy_configured, - ) - from prowler.providers.m365.services.defender.defender_service import ( - AntiphishingPolicy, - ) - defender_client.antiphishing_policies = { "Default": AntiphishingPolicy( + name="Default", spoof_intelligence=True, spoof_intelligence_action="Quarantine", dmarc_reject_action="Quarantine", @@ -158,27 +206,149 @@ class Test_defender_antiphishing_policy_configured: show_tag=True, honor_dmarc_policy=True, default=True, + ), + "Policy1": AntiphishingPolicy( + name="Policy1", + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=False, + ), + } + defender_client.antiphishing_rules = { + "Policy1": AntiphishingRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], ) } - defender_client.antiphising_rules = {} check = defender_antiphishing_policy_configured() result = check.execute() - assert len(result) == 1 + assert len(result) == 2 assert result[0].status == "PASS" assert ( result[0].status_extended - == "Anti-phishing policy Default is properly configured and enabled." + == "Default is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert ( result[0].resource == defender_client.antiphishing_policies["Default"].dict() ) - assert result[0].resource_name == "Defender Anti-Phishing Policy" - assert result[0].resource_id == "Default" - assert result[0].location == "global" - def test_default_policy_not_properly_configured(self): + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Anti-phishing policy Policy1 is not properly configured and includes users: test@example.com; groups: example_group; domains: example.com, " + "with priority 1 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.antiphishing_policies["Policy1"].dict() + ) + + def test_case_4_default_not_ok_potential_false_positive(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + AntiphishingRule, + ) + + defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + name="Default", + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=True, + ), + "Policy1": AntiphishingPolicy( + name="Policy1", + spoof_intelligence=True, + spoof_intelligence_action="Quarantine", + dmarc_reject_action="Quarantine", + dmarc_quarantine_action="Quarantine", + safety_tips=True, + unauthenticated_sender_action=True, + show_tag=True, + honor_dmarc_policy=True, + default=False, + ), + } + defender_client.antiphishing_rules = { + "Policy1": AntiphishingRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ) + } + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Anti-phishing policy Policy1 is properly configured and includes users: test@example.com; groups: example_group; domains: example.com, " + f"with priority {defender_client.antiphishing_rules['Policy1'].priority} (0 is the highest). " + "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.antiphishing_policies["Policy1"].dict() + ) + + def test_case_5_default_policy_not_properly_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -205,6 +375,7 @@ class Test_defender_antiphishing_policy_configured: defender_client.antiphishing_policies = { "Default": AntiphishingPolicy( + name="Default", spoof_intelligence=False, spoof_intelligence_action="None", dmarc_reject_action="None", @@ -216,7 +387,7 @@ class Test_defender_antiphishing_policy_configured: default=True, ) } - defender_client.antiphising_rules = {} + defender_client.antiphishing_rules = {} check = defender_antiphishing_policy_configured() result = check.execute() @@ -224,15 +395,103 @@ class Test_defender_antiphishing_policy_configured: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Anti-phishing policy Default is not properly configured." + == "Default is the only policy and it's not properly configured in the default Defender Anti-Phishing Policy." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert ( result[0].resource == defender_client.antiphishing_policies["Default"].dict() ) - assert result[0].resource_name == "Defender Anti-Phishing Policy" + + def test_case_6_both_policies_not_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( + defender_antiphishing_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + AntiphishingPolicy, + AntiphishingRule, + ) + + defender_client.antiphishing_policies = { + "Default": AntiphishingPolicy( + name="Default", + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=True, + ), + "Policy1": AntiphishingPolicy( + name="Policy1", + spoof_intelligence=False, + spoof_intelligence_action="None", + dmarc_reject_action="None", + dmarc_quarantine_action="None", + safety_tips=False, + unauthenticated_sender_action=False, + show_tag=False, + honor_dmarc_policy=False, + default=False, + ), + } + defender_client.antiphishing_rules = { + "Policy1": AntiphishingRule( + state="Enabled", + priority=1, + users=[], + groups=[], + domains=["example.com"], + ) + } + + check = defender_antiphishing_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" assert result[0].resource_id == "Default" - assert result[0].location == "global" + assert ( + result[0].resource + == defender_client.antiphishing_policies["Default"].dict() + ) + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Anti-phishing policy Policy1 is not properly configured and includes domains: example.com, " + "with priority 1 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.antiphishing_policies["Policy1"].dict() + ) def test_no_antiphishing_policies(self): defender_client = mock.MagicMock() @@ -257,64 +516,8 @@ class Test_defender_antiphishing_policy_configured: ) defender_client.antiphishing_policies = {} - defender_client.antiphising_rules = {} + defender_client.antiphishing_rules = {} check = defender_antiphishing_policy_configured() result = check.execute() - assert result == [] - - def test_custom_policy_without_rule(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import ( - defender_antiphishing_policy_configured, - ) - from prowler.providers.m365.services.defender.defender_service import ( - AntiphishingPolicy, - ) - - defender_client.antiphishing_policies = { - "PolicyX": AntiphishingPolicy( - spoof_intelligence=True, - spoof_intelligence_action="Quarantine", - dmarc_reject_action="Quarantine", - dmarc_quarantine_action="Quarantine", - safety_tips=True, - unauthenticated_sender_action=True, - show_tag=True, - honor_dmarc_policy=True, - default=False, - ) - } - defender_client.antiphising_rules = {} - - check = defender_antiphishing_policy_configured() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Anti-phishing policy PolicyX is not properly configured." - ) - assert ( - result[0].resource - == defender_client.antiphishing_policies["PolicyX"].dict() - ) - assert result[0].resource_name == "Defender Anti-Phishing Policy" - assert result[0].resource_id == "PolicyX" - assert result[0].location == "global" + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py index dbb3ee3344..7baedbeb61 100644 --- a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py @@ -4,119 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_antispam_outbound_policy_configured: - def test_properly_configured_custom_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( - defender_antispam_outbound_policy_configured, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - OutboundSpamRule, - ) - - defender_client.outbound_spam_policies = { - "Policy1": OutboundSpamPolicy( - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - default=False, - auto_forwarding_mode=False, - ) - } - defender_client.outbound_spam_rules = { - "Policy1": OutboundSpamRule(state="Enabled") - } - - check = defender_antispam_outbound_policy_configured() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == "Outbound Spam Policy Policy1 is properly configured and enabled." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["Policy1"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Policy1" - assert result[0].location == "global" - - def test_not_properly_configured_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( - defender_antispam_outbound_policy_configured, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - OutboundSpamRule, - ) - - defender_client.outbound_spam_policies = { - "Policy2": OutboundSpamPolicy( - notify_sender_blocked=False, - notify_limit_exceeded=False, - notify_limit_exceeded_addresses=[], - notify_sender_blocked_addresses=[], - default=False, - auto_forwarding_mode=False, - ) - } - defender_client.outbound_spam_rules = { - "Policy2": OutboundSpamRule(state="Enabled") - } - - check = defender_antispam_outbound_policy_configured() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Outbound Spam Policy Policy2 is not properly configured." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["Policy2"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Policy2" - assert result[0].location == "global" - - def test_properly_configured_default_policy(self): + def test_case_1_default_policy_properly_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -143,12 +31,13 @@ class Test_defender_antispam_outbound_policy_configured: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( - notify_sender_blocked=True, + name="Default", notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - default=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], auto_forwarding_mode=False, + default=True, ) } defender_client.outbound_spam_rules = {} @@ -159,17 +48,271 @@ class Test_defender_antispam_outbound_policy_configured: assert result[0].status == "PASS" assert ( result[0].status_extended - == "Outbound Spam Policy Default is properly configured and enabled." + == "Default is the only policy and it's properly configured in the default Defender Outbound Spam Policy." ) + assert ( + result[0].resource_name + == defender_client.outbound_spam_policies["Default"].name + ) + assert result[0].resource_id == "Default" assert ( result[0].resource == defender_client.outbound_spam_policies["Default"].dict() ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Default" - assert result[0].location == "global" - def test_policy_without_rule(self): + def test_case_2_all_policies_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + auto_forwarding_mode=False, + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + auto_forwarding_mode=False, + default=False, + ), + } + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 is properly configured and includes users: test@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_3_default_ok_others_not(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + auto_forwarding_mode=False, + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + auto_forwarding_mode=False, + default=False, + ), + } + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 is not properly configured and includes users: test@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_4_default_not_ok_custom_good(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + auto_forwarding_mode=False, + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + auto_forwarding_mode=False, + default=False, + ), + } + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=0, + users=["user1@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 is properly configured and includes users: user1@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_5_only_default_not_ok(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -195,13 +338,14 @@ class Test_defender_antispam_outbound_policy_configured: ) defender_client.outbound_spam_policies = { - "PolicyX": OutboundSpamPolicy( - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["admin@org.com"], - notify_sender_blocked_addresses=["admin@org.com"], - default=False, + "Default": OutboundSpamPolicy( + name="Default", + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], auto_forwarding_mode=False, + default=True, ) } defender_client.outbound_spam_rules = {} @@ -212,15 +356,98 @@ class Test_defender_antispam_outbound_policy_configured: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Outbound Spam Policy PolicyX is not properly configured." + == "Default is the only policy and it's not properly configured in the default Defender Outbound Spam Policy." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert ( result[0].resource - == defender_client.outbound_spam_policies["PolicyX"].dict() + == defender_client.outbound_spam_policies["Default"].dict() + ) + + def test_case_6_default_and_custom_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import ( + defender_antispam_outbound_policy_configured, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + auto_forwarding_mode=False, + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + auto_forwarding_mode=False, + default=False, + ), + } + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=5, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_outbound_policy_configured() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 is not properly configured and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 5 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "PolicyX" - assert result[0].location == "global" def test_no_outbound_spam_policies(self): defender_client = mock.MagicMock() diff --git a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py index 0e911a33b2..64fce5f88b 100644 --- a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py @@ -4,6 +4,456 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_antispam_outbound_policy_forwarding_disabled: + def test_case_1_default_policy_forwarding_disabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=False, + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + default=True, + ) + } + defender_client.outbound_spam_rules = {} + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the only policy and mail forwarding is disabled." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + def test_case_2_all_policies_forwarding_disabled(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=False, + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + auto_forwarding_mode=False, + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + default=False, + ), + } + + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and mail forwarding is disabled, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 disables mail forwarding and includes users: test@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). Also, the default policy disables mail forwarding, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_3_default_ok_custom_not(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=False, + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + auto_forwarding_mode=True, + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=False, + ), + } + + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and mail forwarding is disabled, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 allows mail forwarding and includes users: test@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). However, the default policy disables mail forwarding, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_4_default_not_ok_custom_good(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=True, + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + auto_forwarding_mode=False, + notify_limit_exceeded=True, + notify_sender_blocked=True, + notify_limit_exceeded_addresses=["admin@example.com"], + notify_sender_blocked_addresses=["admin@example.com"], + default=False, + ), + } + + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=0, + users=["user1@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and mail forwarding is allowed, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 disables mail forwarding and includes users: user1@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + + def test_case_5_only_default_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=True, + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=True, + ) + } + defender_client.outbound_spam_rules = {} + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the only policy and mail forwarding is allowed." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + def test_case_6_default_and_custom_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( + defender_antispam_outbound_policy_forwarding_disabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + OutboundSpamPolicy, + OutboundSpamRule, + ) + + defender_client.outbound_spam_policies = { + "Default": OutboundSpamPolicy( + name="Default", + auto_forwarding_mode=True, + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=True, + ), + "Policy1": OutboundSpamPolicy( + name="Policy1", + auto_forwarding_mode=True, + notify_limit_exceeded=False, + notify_sender_blocked=False, + notify_limit_exceeded_addresses=[], + notify_sender_blocked_addresses=[], + default=False, + ), + } + + defender_client.outbound_spam_rules = { + "Policy1": OutboundSpamRule( + state="Enabled", + priority=1, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_outbound_policy_forwarding_disabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and mail forwarding is allowed, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert ( + result[0].resource + == defender_client.outbound_spam_policies["Default"].dict() + ) + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Outbound Spam policy Policy1 allows mail forwarding and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 1 (0 is the highest). Also, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert ( + result[1].resource + == defender_client.outbound_spam_policies["Policy1"].dict() + ) + def test_no_outbound_spam_policies(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" @@ -32,221 +482,3 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: check = defender_antispam_outbound_policy_forwarding_disabled() result = check.execute() assert len(result) == 0 - - def test_forwarding_disabled_custom_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( - defender_antispam_outbound_policy_forwarding_disabled, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - OutboundSpamRule, - ) - - defender_client.outbound_spam_policies = { - "Policy1": OutboundSpamPolicy( - default=False, - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - auto_forwarding_mode=False, - ) - } - defender_client.outbound_spam_rules = { - "Policy1": OutboundSpamRule(state="Enabled") - } - - check = defender_antispam_outbound_policy_forwarding_disabled() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == "Outbound Spam Policy Policy1 does not allow mail forwarding." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["Policy1"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Policy1" - assert result[0].location == "global" - - def test_forwarding_enabled_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( - defender_antispam_outbound_policy_forwarding_disabled, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - OutboundSpamRule, - ) - - defender_client.outbound_spam_policies = { - "Policy2": OutboundSpamPolicy( - default=False, - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - auto_forwarding_mode=True, - ) - } - defender_client.outbound_spam_rules = { - "Policy2": OutboundSpamRule(state="Enabled") - } - - check = defender_antispam_outbound_policy_forwarding_disabled() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Outbound Spam Policy Policy2 does allow mail forwarding." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["Policy2"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Policy2" - assert result[0].location == "global" - - def test_forwarding_disabled_default_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( - defender_antispam_outbound_policy_forwarding_disabled, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - ) - - defender_client.outbound_spam_policies = { - "Default": OutboundSpamPolicy( - default=True, - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - auto_forwarding_mode=False, - ) - } - defender_client.outbound_spam_rules = {} - - check = defender_antispam_outbound_policy_forwarding_disabled() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == "Outbound Spam Policy Default does not allow mail forwarding." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["Default"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "Default" - assert result[0].location == "global" - - def test_policy_without_rule(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import ( - defender_antispam_outbound_policy_forwarding_disabled, - ) - from prowler.providers.m365.services.defender.defender_service import ( - OutboundSpamPolicy, - ) - - defender_client.outbound_spam_policies = { - "PolicyX": OutboundSpamPolicy( - default=False, - notify_sender_blocked=True, - notify_limit_exceeded=True, - notify_limit_exceeded_addresses=["test@correo.com"], - notify_sender_blocked_addresses=["test@correo.com"], - auto_forwarding_mode=False, - ) - } - defender_client.outbound_spam_rules = {} - - check = defender_antispam_outbound_policy_forwarding_disabled() - result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Outbound Spam Policy PolicyX does allow mail forwarding." - ) - assert ( - result[0].resource - == defender_client.outbound_spam_policies["PolicyX"].dict() - ) - assert result[0].resource_name == "Defender Outbound Spam Policy" - assert result[0].resource_id == "PolicyX" - assert result[0].location == "global" diff --git a/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py b/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py index feba0c5bb4..625fc8ded3 100644 --- a/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_policy_inbound_no_allowed_domains/defender_antispam_policy_inbound_no_allowed_domains_test.py @@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_antispam_policy_inbound_no_allowed_domains: - def test_policy_without_allowed_domains(self): + def test_case_1_default_policy_no_allowed_domains(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -31,26 +31,240 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains: defender_client.inbound_spam_policies = [ DefenderInboundSpamPolicy( - identity="Policy1", + identity="Default", + default=True, allowed_sender_domains=[], ) ] + defender_client.inbound_spam_rules = {} check = defender_antispam_policy_inbound_no_allowed_domains() result = check.execute() - assert len(result) == 1 assert result[0].status == "PASS" assert ( result[0].status_extended - == "Inbound anti-spam policy Policy1 does not contain allowed domains." + == "Default is the only policy and it does not contain allowed domains." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.inbound_spam_policies[0].dict() - assert result[0].resource_name == "Defender Inbound Spam Policy" - assert result[0].resource_id == "Policy1" - assert result[0].location == "global" - def test_policy_with_allowed_domains(self): + def test_case_2_all_policies_no_allowed_domains(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + InboundSpamRule, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Default", + default=True, + allowed_sender_domains=[], + ), + DefenderInboundSpamPolicy( + identity="Policy1", + default=False, + allowed_sender_domains=[], + ), + ] + defender_client.inbound_spam_rules = { + "Policy1": InboundSpamRule( + state="Enabled", + priority=1, + users=["user1@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and it does not contain allowed domains, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Inbound Spam policy Policy1 does not contain allowed domains and includes users: user1@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). Also, the default policy does not contain allowed domains, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.inbound_spam_policies[1].dict() + + def test_case_3_default_ok_custom_with_allowed_domains(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + InboundSpamRule, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Default", + default=True, + allowed_sender_domains=[], + ), + DefenderInboundSpamPolicy( + identity="Policy1", + default=False, + allowed_sender_domains=["spam.com"], + ), + ] + defender_client.inbound_spam_rules = { + "Policy1": InboundSpamRule( + state="Enabled", + priority=2, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and it does not contain allowed domains, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Inbound Spam policy Policy1 contains allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 2 (0 is the highest). However, the default policy does not contain allowed domains, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.inbound_spam_policies[1].dict() + + def test_case_4_default_with_allowed_domains_custom_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + InboundSpamRule, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Default", + default=True, + allowed_sender_domains=["example.org"], + ), + DefenderInboundSpamPolicy( + identity="Policy1", + default=False, + allowed_sender_domains=[], + ), + ] + + defender_client.inbound_spam_rules = { + "Policy1": InboundSpamRule( + state="Enabled", + priority=0, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and it contains allowed domains: example.org, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Inbound Spam policy Policy1 does not contain allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy contains allowed domains, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.inbound_spam_policies[1].dict() + + def test_case_5_default_with_allowed_domains(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -77,24 +291,96 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains: defender_client.inbound_spam_policies = [ DefenderInboundSpamPolicy( - identity="Policy2", - allowed_sender_domains=["bad-domain.com"], + identity="Default", + default=True, + allowed_sender_domains=["example.com"], ) ] + defender_client.inbound_spam_rules = {} check = defender_antispam_policy_inbound_no_allowed_domains() result = check.execute() - assert len(result) == 1 assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Inbound anti-spam policy Policy2 contains allowed domains: ['bad-domain.com']." + == "Default is the only policy and it contains allowed domains: example.com." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.inbound_spam_policies[0].dict() - assert result[0].resource_name == "Defender Inbound Spam Policy" - assert result[0].resource_id == "Policy2" - assert result[0].location == "global" + + def test_case_6_both_default_and_custom_with_allowed_domains(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import ( + defender_antispam_policy_inbound_no_allowed_domains, + ) + from prowler.providers.m365.services.defender.defender_service import ( + DefenderInboundSpamPolicy, + InboundSpamRule, + ) + + defender_client.inbound_spam_policies = [ + DefenderInboundSpamPolicy( + identity="Default", + default=True, + allowed_sender_domains=["example.com"], + ), + DefenderInboundSpamPolicy( + identity="Policy1", + default=False, + allowed_sender_domains=["spam.com"], + ), + ] + + defender_client.inbound_spam_rules = { + "Policy1": InboundSpamRule( + state="Enabled", + priority=5, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_antispam_policy_inbound_no_allowed_domains() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and it contains allowed domains: example.com, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.inbound_spam_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Inbound Spam policy Policy1 contains allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 5 (0 is the highest). Also, the default policy contains allowed domains, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.inbound_spam_policies[1].dict() def test_no_inbound_spam_policies(self): defender_client = mock.MagicMock() @@ -119,8 +405,8 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains: ) defender_client.inbound_spam_policies = [] + defender_client.inbound_spam_rules = {} check = defender_antispam_policy_inbound_no_allowed_domains() result = check.execute() - assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py index d7cbb59d9e..adb62b213d 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_common_attachments_filter_enabled/defender_malware_policy_common_attachments_filter_enabled_test.py @@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_malware_policy_common_attachments_filter_enabled: - def test_enable_file_filter_disabled(self): + def test_case_1_only_default_policy_enabled(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -31,30 +31,29 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: defender_client.malware_policies = [ MalwarePolicy( - enable_file_filter=False, - identity="Policy1", - enable_internal_sender_admin_notifications=False, - internal_sender_admin_address="", - file_types=[], + identity="Default", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "js"], is_default=True, - ), + ) ] + defender_client.malware_rules = {} check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() assert len(result) == 1 - - assert result[0].status == "FAIL" + assert result[0].status == "PASS" assert ( result[0].status_extended - == "Common Attachment Types Filter is not enabled in anti-malware policy Policy1." + == "Default is the only policy and Common Attachment Types Filter is enabled." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - def test_enable_file_filter_enabled(self): + def test_case_2_all_policies_enabled(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -77,34 +76,345 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: ) from prowler.providers.m365.services.defender.defender_service import ( MalwarePolicy, + MalwareRule, ) defender_client.malware_policies = [ MalwarePolicy( + identity="Default", enable_file_filter=True, - identity="Policy1", - enable_internal_sender_admin_notifications=False, - internal_sender_admin_address="", - file_types=[], + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "js"], is_default=True, ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], + is_default=False, + ), ] + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=1, + users=["user1@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() - assert len(result) == 1 + assert len(result) == 2 assert result[0].status == "PASS" assert ( result[0].status_extended - == "Common Attachment Types Filter is enabled in anti-malware policy Policy1." + == "Default is the default policy and Common Attachment Types Filter is enabled, but it could be overridden by another misconfigured Custom Policy." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - def test_no_policy(self): + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 enables Common Attachment Types Filter and includes users: user1@example.com; groups: group1; domains: domain.com, " + "with priority 1 (0 is the highest). Also, the default policy enables the filter, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_3_default_ok_custom_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["js"], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=2, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is enabled, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 does not enable Common Attachment Types Filter and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 2 (0 is the highest). However, the default policy enables the filter, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_4_default_not_ok_custom_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=0, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is not enabled, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 enables Common Attachment Types Filter and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_5_only_default_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ) + ] + defender_client.malware_rules = {} + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the only policy and Common Attachment Types Filter is not enabled." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + def test_case_6_default_and_custom_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import ( + defender_malware_policy_common_attachments_filter_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=5, + users=["user1@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_malware_policy_common_attachments_filter_enabled() + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is not enabled, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 does not enable Common Attachment Types Filter and includes users: user1@example.com; groups: group1; domains: domain.com, " + "with priority 5 (0 is the highest). Also, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_no_malware_policies(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -127,16 +437,8 @@ class Test_defender_malware_policy_common_attachments_filter_enabled: ) defender_client.malware_policies = [] + defender_client.malware_rules = {} check = defender_malware_policy_common_attachments_filter_enabled() result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Common Attachment Types Filter is not enabled." - ) - assert result[0].resource == {} - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied_test.py b/tests/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied_test.py index 9977de9a54..682f86c768 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_comprehensive_attachments_filter_applied/defender_malware_policy_comprehensive_attachments_filter_applied_test.py @@ -1,53 +1,10 @@ from unittest import mock -from prowler.providers.m365.services.defender.defender_service import ( - MalwarePolicy, - MalwareRule, -) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_malware_policy_comprehensive_attachments_filter_applied: - def test_no_policy(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - defender_client.malware_policies = [] - defender_client.audit_config = {} - defender_client.malware_rules = {} - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( - defender_malware_policy_comprehensive_attachments_filter_applied, - ) - - check = defender_malware_policy_comprehensive_attachments_filter_applied() - result = check.execute() - - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Common Attachment Types Filter is not enabled." - ) - assert result[0].resource == {} - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - - def test_policy_enabled_all_extensions_blocked(self): + def test_case_1_default_policy_properly_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -68,192 +25,430 @@ class Test_defender_malware_policy_comprehensive_attachments_filter_applied: from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( defender_malware_policy_comprehensive_attachments_filter_applied, ) - - valid_extensions = ["exe", "bat", "js"] - defender_client.audit_config = { - "recommended_blocked_file_types": valid_extensions - } - defender_client.malware_rules = {"PolicyGood": MalwareRule(state="Enabled")} - defender_client.malware_policies = [ - MalwarePolicy( - enable_file_filter=True, - identity="PolicyGood", - enable_internal_sender_admin_notifications=True, - internal_sender_admin_address="admin@example.com", - file_types=valid_extensions, - is_default=True, - ) - ] - - check = defender_malware_policy_comprehensive_attachments_filter_applied() - result = check.execute() - - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == "Common Attachment Types Filter is enabled in anti-malware policy PolicyGood, the policy is enabled and the filter is applied to the recommended file types." - ) - assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - - def test_policy_enabled_missing_extensions(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( - defender_malware_policy_comprehensive_attachments_filter_applied, + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, ) defender_client.audit_config = { "recommended_blocked_file_types": ["exe", "bat", "js"] } - defender_client.malware_rules = { - "PolicyPartial": MalwareRule(state="Enabled") - } defender_client.malware_policies = [ MalwarePolicy( + identity="Default", enable_file_filter=True, - identity="PolicyPartial", enable_internal_sender_admin_notifications=True, internal_sender_admin_address="admin@example.com", - file_types=["exe"], + file_types=["exe", "bat", "js"], is_default=True, ) ] - - check = defender_malware_policy_comprehensive_attachments_filter_applied() - result = check.execute() - - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Common Attachment Types Filter is enabled in anti-malware policy PolicyPartial, but the following recommended file types are missing: bat, js." - ) - assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - - def test_policy_enabled_but_rule_disabled(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( - defender_malware_policy_comprehensive_attachments_filter_applied, - ) - - valid_extensions = ["exe"] - defender_client.audit_config = { - "recommended_blocked_file_types": valid_extensions - } - defender_client.malware_rules = { - "PolicyDisabled": MalwareRule(state="Disabled") - } - defender_client.malware_policies = [ - MalwarePolicy( - enable_file_filter=True, - identity="PolicyDisabled", - enable_internal_sender_admin_notifications=True, - internal_sender_admin_address="admin@example.com", - file_types=valid_extensions, - is_default=False, - ) - ] - - check = defender_malware_policy_comprehensive_attachments_filter_applied() - result = check.execute() - - assert len(result) == 1 - assert result[0].status == "FAIL" - assert ( - result[0].status_extended - == "Common Attachment Types Filter is enabled in anti-malware policy PolicyDisabled, but the policy is disabled." - ) - assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - - def test_policy_enabled_but_no_rule_and_not_default(self): - defender_client = mock.MagicMock() - defender_client.audited_tenant = "audited_tenant" - defender_client.audited_domain = DOMAIN - - with ( - mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_m365_provider(), - ), - mock.patch( - "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" - ), - mock.patch( - "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", - new=defender_client, - ), - ): - from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( - defender_malware_policy_comprehensive_attachments_filter_applied, - ) - - valid_extensions = ["exe"] - defender_client.audit_config = { - "recommended_blocked_file_types": valid_extensions - } defender_client.malware_rules = {} - defender_client.malware_policies = [ - MalwarePolicy( - enable_file_filter=True, - identity="PolicyNoRule", - enable_internal_sender_admin_notifications=True, - internal_sender_admin_address="admin@example.com", - file_types=valid_extensions, - is_default=False, - ) - ] check = defender_malware_policy_comprehensive_attachments_filter_applied() result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the only policy and Common Attachment Types Filter is properly configured." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + def test_case_2_all_policies_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.audit_config = { + "recommended_blocked_file_types": ["exe", "bat"] + } + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "bat"], + is_default=True, + ), + MalwarePolicy( + identity="Custom1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "bat"], + is_default=False, + ), + ] + defender_client.malware_rules = { + "Custom1": MalwareRule( + state="Enabled", + priority=1, + users=["user1@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is properly configured, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Custom1 is properly configured and includes users: user1@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Custom1" + assert result[1].resource_id == "Custom1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_3_default_ok_custom_not(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.audit_config = { + "recommended_blocked_file_types": ["exe", "bat"] + } + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "bat"], + is_default=True, + ), + MalwarePolicy( + identity="Custom1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], # missing bat + is_default=False, + ), + ] + defender_client.malware_rules = { + "Custom1": MalwareRule( + state="Enabled", + priority=1, + users=["user1@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is properly configured, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Custom1 is not properly configured and includes users: user1@example.com; groups: group1; domains: example.com, " + "with priority 1 (0 is the highest). Missing recommended file types: bat. However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Custom1" + assert result[1].resource_id == "Custom1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_4_default_not_ok_custom_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.audit_config = { + "recommended_blocked_file_types": ["exe", "bat"] + } + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Custom1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe", "bat"], + is_default=False, + ), + ] + defender_client.malware_rules = { + "Custom1": MalwareRule( + state="Enabled", + priority=0, + users=["user1@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is not properly configured, but it could be overridden by another well-configured Custom Policy. Missing recommended file types: exe, bat." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Custom1 is properly configured and includes users: user1@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Custom1" + assert result[1].resource_id == "Custom1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_5_only_default_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + ) + + defender_client.audit_config = { + "recommended_blocked_file_types": ["exe", "bat"] + } + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ) + ] + defender_client.malware_rules = {} + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Common Attachment Types Filter is not properly configured in anti-malware policy PolicyNoRule." + == "Default is the only policy and Common Attachment Types Filter is not properly configured. Missing recommended file types: exe, bat." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" + + def test_case_6_default_and_custom_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.audit_config = { + "recommended_blocked_file_types": ["exe", "bat"] + } + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Custom1", + enable_file_filter=True, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=["exe"], # missing bat + is_default=False, + ), + ] + defender_client.malware_rules = { + "Custom1": MalwareRule( + state="Enabled", + priority=2, + users=["user@example.com"], + groups=["group1"], + domains=["example.com"], + ) + } + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() + assert len(result) == 2 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and Common Attachment Types Filter is not properly configured, but it could be overridden by another well-configured Custom Policy. Missing recommended file types: exe, bat." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Custom1 is not properly configured and includes users: user@example.com; groups: group1; domains: example.com, " + "with priority 2 (0 is the highest). Missing recommended file types: bat. Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Custom1" + assert result[1].resource_id == "Custom1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_no_malware_policies(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + defender_client.malware_policies = [] + defender_client.malware_rules = {} + defender_client.audit_config = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import ( + defender_malware_policy_comprehensive_attachments_filter_applied, + ) + + check = defender_malware_policy_comprehensive_attachments_filter_applied() + result = check.execute() + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py index fdd26415d0..16fe656c2b 100644 --- a/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py +++ b/tests/providers/m365/services/defender/defender_malware_policy_notifications_internal_users_malware_enabled/defender_malware_policy_notifications_internal_users_malware_enabled_test.py @@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider class Test_defender_malware_policy_notifications_internal_users_malware_enabled: - def test_notifications_disabled(self): + def test_case_1_default_properly_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -31,32 +31,322 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: defender_client.malware_policies = [ MalwarePolicy( - enable_file_filter=True, identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ) + ] + defender_client.malware_rules = {} + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the only policy and notifications for internal users sending malware are enabled." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + def test_case_2_default_and_custom_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=1, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and notifications for internal users sending malware are enabled, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 is properly configured and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_3_default_ok_custom_not_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + file_types=[], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=2, + users=["internal@example.com"], + groups=["group2"], + domains=["example.org"], + ) + } + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Default is the default policy and notifications for internal users sending malware are enabled, but it could be overridden by another misconfigured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 is not properly configured and includes users: internal@example.com; groups: group2; domains: example.org, " + "with priority 2 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_4_default_not_ok_custom_properly_configured(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + MalwareRule, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + file_types=[], + is_default=True, + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=True, + internal_sender_admin_address="admin@example.com", + file_types=[], + is_default=False, + ), + ] + + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=0, + users=["user@example.com"], + groups=["group1"], + domains=["domain.com"], + ) + } + + check = ( + defender_malware_policy_notifications_internal_users_malware_enabled() + ) + result = check.execute() + assert len(result) == 2 + + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Default is the default policy and notifications for internal users sending malware are not enabled, but it could be overridden by another well-configured Custom Policy." + ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" + assert result[0].resource == defender_client.malware_policies[0].dict() + + assert result[1].status == "PASS" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 is properly configured and includes users: user@example.com; groups: group1; domains: domain.com, " + "with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_case_5_only_default_not_ok(self): + defender_client = mock.MagicMock() + defender_client.audited_tenant = "audited_tenant" + defender_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client", + new=defender_client, + ), + ): + from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( + defender_malware_policy_notifications_internal_users_malware_enabled, + ) + from prowler.providers.m365.services.defender.defender_service import ( + MalwarePolicy, + ) + + defender_client.malware_policies = [ + MalwarePolicy( + identity="Default", + enable_file_filter=False, enable_internal_sender_admin_notifications=False, internal_sender_admin_address="", file_types=[], is_default=True, ) ] + defender_client.malware_rules = {} check = ( defender_malware_policy_notifications_internal_users_malware_enabled() ) result = check.execute() - assert len(result) == 1 assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Notifications for internal users sending malware are not enabled." + == "Default is the only policy and notifications for internal users sending malware are not enabled." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - def test_notifications_enabled_without_email(self): + def test_case_6_default_and_custom_not_configured(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -79,36 +369,64 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: ) from prowler.providers.m365.services.defender.defender_service import ( MalwarePolicy, + MalwareRule, ) defender_client.malware_policies = [ MalwarePolicy( - enable_file_filter=True, identity="Default", - enable_internal_sender_admin_notifications=True, + enable_file_filter=False, + enable_internal_sender_admin_notifications=False, internal_sender_admin_address="", file_types=[], is_default=True, - ) + ), + MalwarePolicy( + identity="Policy1", + enable_file_filter=False, + enable_internal_sender_admin_notifications=False, + internal_sender_admin_address="", + file_types=[], + is_default=False, + ), ] + defender_client.malware_rules = { + "Policy1": MalwareRule( + state="Enabled", + priority=3, + users=["u@example.com"], + groups=["g1"], + domains=["d.com"], + ) + } + check = ( defender_malware_policy_notifications_internal_users_malware_enabled() ) result = check.execute() + assert len(result) == 2 - assert len(result) == 1 assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Notifications for internal users sending malware are enabled, but no email addresses are configured." + == "Default is the default policy and notifications for internal users sending malware are not enabled, but it could be overridden by another well-configured Custom Policy." ) + assert result[0].resource_name == "Default" + assert result[0].resource_id == "Default" assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" - def test_notifications_enabled_with_email(self): + assert result[1].status == "FAIL" + assert ( + result[1].status_extended + == "Custom Malware policy Policy1 is not properly configured and includes users: u@example.com; groups: g1; domains: d.com, " + "with priority 3 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected." + ) + assert result[1].resource_name == "Policy1" + assert result[1].resource_id == "Policy1" + assert result[1].resource == defender_client.malware_policies[1].dict() + + def test_no_malware_policies(self): defender_client = mock.MagicMock() defender_client.audited_tenant = "audited_tenant" defender_client.audited_domain = DOMAIN @@ -129,33 +447,12 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled: from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import ( defender_malware_policy_notifications_internal_users_malware_enabled, ) - from prowler.providers.m365.services.defender.defender_service import ( - MalwarePolicy, - ) - defender_client.malware_policies = [ - MalwarePolicy( - enable_file_filter=True, - identity="Default", - enable_internal_sender_admin_notifications=True, - internal_sender_admin_address="security@example.com", - file_types=[], - is_default=True, - ) - ] + defender_client.malware_policies = [] + defender_client.malware_rules = {} check = ( defender_malware_policy_notifications_internal_users_malware_enabled() ) result = check.execute() - - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == "Notifications for internal users sending malware are enabled." - ) - assert result[0].resource == defender_client.malware_policies[0].dict() - assert result[0].resource_name == "Defender Malware Policy" - assert result[0].resource_id == "defenderMalwarePolicy" - assert result[0].location == "global" + assert len(result) == 0 diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 3e5a534f2c..35534a53e3 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -9,6 +9,7 @@ from prowler.providers.m365.services.defender.defender_service import ( Defender, DefenderInboundSpamPolicy, DkimConfig, + InboundSpamRule, MalwarePolicy, MalwareRule, OutboundSpamPolicy, @@ -41,14 +42,27 @@ def mock_defender_get_malware_filter_policy(_): def mock_defender_get_malware_filter_rule(_): return { - "Policy1": MalwareRule(state="Enabled"), - "Policy2": MalwareRule(state="Disabled"), + "Policy1": MalwareRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ), + "Policy2": MalwareRule( + state="Disabled", + priority=2, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ), } -def mock_defender_get_antiphising_policy(_): +def mock_defender_get_antiphishing_policy(_): return { "Policy1": AntiphishingPolicy( + name="Policy1", spoof_intelligence=True, spoof_intelligence_action="Quarantine", dmarc_reject_action="Reject", @@ -60,6 +74,7 @@ def mock_defender_get_antiphising_policy(_): default=False, ), "Policy2": AntiphishingPolicy( + name="Policy2", spoof_intelligence=False, spoof_intelligence_action="None", dmarc_reject_action="None", @@ -73,13 +88,21 @@ def mock_defender_get_antiphising_policy(_): } -def mock_defender_get_antiphising_rules(_): +def mock_defender_get_antiphishing_rules(_): return { "Policy1": AntiphishingRule( state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], ), "Policy2": AntiphishingRule( state="Disabled", + priority=2, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], ), } @@ -89,14 +112,35 @@ def mock_defender_get_inbound_spam_policy(_): DefenderInboundSpamPolicy( identity="Policy1", allowed_sender_domains=[], + default=False, ), DefenderInboundSpamPolicy( identity="Policy2", allowed_sender_domains=["example.com"], + default=True, ), ] +def mock_defender_get_inbound_spam_rule(_): + return { + "Policy1": InboundSpamRule( + state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ), + "Policy2": InboundSpamRule( + state="Disabled", + priority=2, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], + ), + } + + def mock_defender_get_connection_filter_policy(_): return ConnectionFilterPolicy( ip_allow_list=[], @@ -131,6 +175,7 @@ def mock_defender_get_report_submission_policy(_): def mock_defender_get_outbound_spam_filter_policy(_): return { "Policy1": OutboundSpamPolicy( + name="Policy1", notify_sender_blocked=True, notify_limit_exceeded=True, notify_limit_exceeded_addresses=["security@example.com"], @@ -139,6 +184,7 @@ def mock_defender_get_outbound_spam_filter_policy(_): default=False, ), "Policy2": OutboundSpamPolicy( + name="Policy2", notify_sender_blocked=False, notify_limit_exceeded=False, notify_limit_exceeded_addresses=[], @@ -153,9 +199,17 @@ def mock_defender_get_outbound_spam_filter_rule(_): return { "Policy1": OutboundSpamRule( state="Enabled", + priority=1, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], ), "Policy2": OutboundSpamRule( state="Disabled", + priority=2, + users=["test@example.com"], + groups=["example_group"], + domains=["example.com"], ), } @@ -230,14 +284,22 @@ class Test_Defender_Service: ) malware_rules = defender_client.malware_rules assert malware_rules["Policy1"].state == "Enabled" + assert malware_rules["Policy1"].priority == 1 + assert malware_rules["Policy1"].users == ["test@example.com"] + assert malware_rules["Policy1"].groups == ["example_group"] + assert malware_rules["Policy1"].domains == ["example.com"] assert malware_rules["Policy2"].state == "Disabled" + assert malware_rules["Policy2"].priority == 2 + assert malware_rules["Policy2"].users == ["test@example.com"] + assert malware_rules["Policy2"].groups == ["example_group"] + assert malware_rules["Policy2"].domains == ["example.com"] defender_client.powershell.close() @patch( - "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_policy", - new=mock_defender_get_antiphising_policy, + "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphishing_policy", + new=mock_defender_get_antiphishing_policy, ) - def test_get_antiphising_policy(self): + def test_get_antiphishing_policy(self): with ( mock.patch( "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" @@ -249,6 +311,7 @@ class Test_Defender_Service: ) ) antiphishing_policies = defender_client.antiphishing_policies + assert antiphishing_policies["Policy1"].name == "Policy1" assert antiphishing_policies["Policy1"].spoof_intelligence is True assert ( antiphishing_policies["Policy1"].spoof_intelligence_action @@ -265,6 +328,7 @@ class Test_Defender_Service: assert antiphishing_policies["Policy1"].show_tag is True assert antiphishing_policies["Policy1"].honor_dmarc_policy is True assert antiphishing_policies["Policy1"].default is False + assert antiphishing_policies["Policy2"].name == "Policy2" assert antiphishing_policies["Policy2"].spoof_intelligence is False assert antiphishing_policies["Policy2"].spoof_intelligence_action == "None" assert antiphishing_policies["Policy2"].dmarc_reject_action == "None" @@ -279,10 +343,10 @@ class Test_Defender_Service: defender_client.powershell.close() @patch( - "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_rules", - new=mock_defender_get_antiphising_rules, + "prowler.providers.m365.services.defender.defender_service.Defender._get_antiphishing_rules", + new=mock_defender_get_antiphishing_rules, ) - def test_get_antiphising_rules(self): + def test_get_antiphishing_rules(self): with ( mock.patch( "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" @@ -293,9 +357,17 @@ class Test_Defender_Service: identity=M365IdentityInfo(tenant_domain=DOMAIN) ) ) - antiphishing_rules = defender_client.antiphising_rules + antiphishing_rules = defender_client.antiphishing_rules assert antiphishing_rules["Policy1"].state == "Enabled" + assert antiphishing_rules["Policy1"].priority == 1 + assert antiphishing_rules["Policy1"].users == ["test@example.com"] + assert antiphishing_rules["Policy1"].groups == ["example_group"] + assert antiphishing_rules["Policy1"].domains == ["example.com"] assert antiphishing_rules["Policy2"].state == "Disabled" + assert antiphishing_rules["Policy2"].priority == 2 + assert antiphishing_rules["Policy2"].users == ["test@example.com"] + assert antiphishing_rules["Policy2"].groups == ["example_group"] + assert antiphishing_rules["Policy2"].domains == ["example.com"] defender_client.powershell.close() @patch( @@ -357,6 +429,7 @@ class Test_Defender_Service: ) ) outbound_spam_policies = defender_client.outbound_spam_policies + assert outbound_spam_policies["Policy1"].name == "Policy1" assert outbound_spam_policies["Policy1"].notify_sender_blocked is True assert outbound_spam_policies["Policy1"].notify_limit_exceeded is True assert outbound_spam_policies[ @@ -367,6 +440,7 @@ class Test_Defender_Service: ].notify_sender_blocked_addresses == ["security@example.com"] assert outbound_spam_policies["Policy1"].auto_forwarding_mode is False assert outbound_spam_policies["Policy1"].default is False + assert outbound_spam_policies["Policy2"].name == "Policy2" assert outbound_spam_policies["Policy2"].notify_sender_blocked is False assert outbound_spam_policies["Policy2"].notify_limit_exceeded is False assert ( @@ -377,6 +451,7 @@ class Test_Defender_Service: ) assert outbound_spam_policies["Policy2"].auto_forwarding_mode is True assert outbound_spam_policies["Policy2"].default is True + defender_client.powershell.close() @patch( "prowler.providers.m365.services.defender.defender_service.Defender._get_outbound_spam_filter_rule", @@ -395,7 +470,16 @@ class Test_Defender_Service: ) outbound_spam_rules = defender_client.outbound_spam_rules assert outbound_spam_rules["Policy1"].state == "Enabled" + assert outbound_spam_rules["Policy1"].priority == 1 + assert outbound_spam_rules["Policy1"].users == ["test@example.com"] + assert outbound_spam_rules["Policy1"].groups == ["example_group"] + assert outbound_spam_rules["Policy1"].domains == ["example.com"] assert outbound_spam_rules["Policy2"].state == "Disabled" + assert outbound_spam_rules["Policy2"].priority == 2 + assert outbound_spam_rules["Policy2"].users == ["test@example.com"] + assert outbound_spam_rules["Policy2"].groups == ["example_group"] + assert outbound_spam_rules["Policy2"].domains == ["example.com"] + defender_client.powershell.close() @patch( "prowler.providers.m365.services.defender.defender_service.Defender._get_inbound_spam_filter_policy", @@ -417,6 +501,34 @@ class Test_Defender_Service: assert inbound_spam_policies[1].allowed_sender_domains == ["example.com"] defender_client.powershell.close() + @patch( + "prowler.providers.m365.services.defender.defender_service.Defender._get_inbound_spam_filter_rule", + new=mock_defender_get_inbound_spam_rule, + ) + def test__get_inbound_spam_filter_rule(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + defender_client = Defender( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + inbound_spam_rules = defender_client.inbound_spam_rules + assert inbound_spam_rules["Policy1"].state == "Enabled" + assert inbound_spam_rules["Policy1"].priority == 1 + assert inbound_spam_rules["Policy1"].users == ["test@example.com"] + assert inbound_spam_rules["Policy1"].groups == ["example_group"] + assert inbound_spam_rules["Policy1"].domains == ["example.com"] + assert inbound_spam_rules["Policy2"].state == "Disabled" + assert inbound_spam_rules["Policy2"].priority == 2 + assert inbound_spam_rules["Policy2"].users == ["test@example.com"] + assert inbound_spam_rules["Policy2"].groups == ["example_group"] + assert inbound_spam_rules["Policy2"].domains == ["example.com"] + defender_client.powershell.close() + @patch( "prowler.providers.m365.services.defender.defender_service.Defender._get_report_submission_policy", new=mock_defender_get_report_submission_policy, From 02d7eaf268a2248e6a04b8841114b9d4d6f3aec4 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 13 May 2025 09:27:27 +0200 Subject: [PATCH 301/359] chore: bump tailwind-merge from 2.5.3 to 3.2.0 (#7722) --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index f86d6169d2..b00fb5b597 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -47,7 +47,7 @@ "server-only": "^0.0.1", "shadcn-ui": "^0.2.3", "sharp": "^0.33.5", - "tailwind-merge": "^2.5.3", + "tailwind-merge": "^3.2.0", "tailwindcss-animate": "^1.0.7", "uuid": "^11.0.5", "zod": "^3.23.8", @@ -14475,9 +14475,9 @@ } }, "node_modules/tailwind-merge": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.3.tgz", - "integrity": "sha512-d9ZolCAIzom1nf/5p4LdD5zvjmgSxY0BGgdSvmXIoMYAiPdAW/dSpP7joCDYFY7r/HkEa2qmPtkgsu0xjQeQtw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.0.tgz", + "integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==", "license": "MIT", "funding": { "type": "github", diff --git a/ui/package.json b/ui/package.json index 13a4ae147e..5d16567d19 100644 --- a/ui/package.json +++ b/ui/package.json @@ -39,7 +39,7 @@ "server-only": "^0.0.1", "shadcn-ui": "^0.2.3", "sharp": "^0.33.5", - "tailwind-merge": "^2.5.3", + "tailwind-merge": "^3.2.0", "tailwindcss-animate": "^1.0.7", "uuid": "^11.0.5", "zod": "^3.23.8", From 80342d612f5e41cef389a98fe8232f79f555fcc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 12:15:14 +0200 Subject: [PATCH 302/359] chore(deps): bump h11 from 0.14.0 to 0.16.0 in /api (#7610) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/poetry.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/poetry.lock b/api/poetry.lock index 02b4bc4fbe..c8e0053ad8 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -4637,6 +4637,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, @@ -4645,6 +4646,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, @@ -4653,6 +4655,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, @@ -4661,6 +4664,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, @@ -4669,6 +4673,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, From 496e0f1e0a862b47d961c6e148e36b6873cffff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Tue, 13 May 2025 12:34:14 +0200 Subject: [PATCH 303/359] fix(overviews): Split in n queries to use database indexes for providers (#7725) --- api/src/backend/api/v1/views.py | 47 ++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 19b21df92e..ded955c93a 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -2513,33 +2513,48 @@ class OverviewViewSet(BaseRLSViewSet): .values_list("id", flat=True) ) - resource_count_queryset = ( - Resource.all_objects.filter( - tenant_id=tenant_id, - provider_id=OuterRef("scan__provider_id"), - ) - .order_by() - .values("provider_id") - .annotate(cnt=Count("id")) - .values("cnt") - ) - - overview_queryset = ( + findings_aggregated = ( ScanSummary.all_objects.filter( tenant_id=tenant_id, scan_id__in=latest_scan_ids ) - .values(provider=F("scan__provider__provider")) + .values( + "scan__provider_id", + provider=F("scan__provider__provider"), + ) .annotate( findings_passed=Coalesce(Sum("_pass"), 0), findings_failed=Coalesce(Sum("fail"), 0), findings_muted=Coalesce(Sum("muted"), 0), total_findings=Coalesce(Sum("total"), 0), - total_resources=Coalesce(Subquery(resource_count_queryset), 0), ) ) - serializer = OverviewProviderSerializer(overview_queryset, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) + resources_aggregated = ( + Resource.all_objects.filter(tenant_id=tenant_id) + .values("provider_id") + .annotate(total_resources=Count("id")) + ) + resource_map = { + row["provider_id"]: row["total_resources"] for row in resources_aggregated + } + + overview = [] + for row in findings_aggregated: + overview.append( + { + "provider": row["provider"], + "total_resources": resource_map.get(row["scan__provider_id"], 0), + "total_findings": row["total_findings"], + "findings_passed": row["findings_passed"], + "findings_failed": row["findings_failed"], + "findings_muted": row["findings_muted"], + } + ) + + return Response( + OverviewProviderSerializer(overview, many=True).data, + status=status.HTTP_200_OK, + ) @action(detail=False, methods=["get"], url_name="findings") def findings(self, request): From 252b664e495b90926c979e209de91873fd6ef105 Mon Sep 17 00:00:00 2001 From: sumit-tft <70506234+sumit-tft@users.noreply.github.com> Date: Tue, 13 May 2025 16:28:23 +0530 Subject: [PATCH 304/359] fix: Added filter to get connected providers only for banner to show (#7723) --- ui/app/(prowler)/scans/page.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx index 04a648986a..737d7f284b 100644 --- a/ui/app/(prowler)/scans/page.tsx +++ b/ui/app/(prowler)/scans/page.tsx @@ -40,7 +40,9 @@ export default async function Scans({ connected: provider.attributes.connection.connected, })) || []; - const providersCountConnected = await getProviders({}); + const providersCountConnected = await getProviders({ + filters: { "filter[connected]": true }, + }); const thereIsNoProviders = !providersCountConnected?.data || providersCountConnected.data.length === 0; From 9baac9fd8972d7f2d67d96d69029a2f9b01efaba Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 13 May 2025 13:10:06 +0200 Subject: [PATCH 305/359] fix(deps): solve h11 package vulnerability (#7696) --- poetry.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 96465562a4..b26ec9a3be 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2184,8 +2184,6 @@ python-versions = "*" groups = ["dev"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, - {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, - {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] From 5c8919372cbf231685ea0ba06a6174c517bb01a4 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Tue, 13 May 2025 13:29:22 +0200 Subject: [PATCH 306/359] fix(deps): solve h11 package vulnerability (#7728) --- api/poetry.lock | 21 ++++++++------------- poetry.lock | 16 ++++++++-------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index c8e0053ad8..a71c16b14b 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2237,14 +2237,14 @@ tornado = ["tornado (>=0.2)"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] @@ -2277,19 +2277,19 @@ files = [ [[package]] name = "httpcore" -version = "1.0.8" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, - {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] @@ -4637,7 +4637,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, @@ -4646,7 +4645,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, @@ -4655,7 +4653,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, @@ -4664,7 +4661,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, @@ -4673,7 +4669,6 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, diff --git a/poetry.lock b/poetry.lock index b26ec9a3be..98d30fac59 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1907,14 +1907,14 @@ typing-extensions = {version = ">=4,<5", markers = "python_version < \"3.10\""} [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] @@ -1947,19 +1947,19 @@ files = [ [[package]] name = "httpcore" -version = "1.0.8" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, - {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] From d548e869fa6199b8aa8dc471de91287086442ad7 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Tue, 13 May 2025 13:41:41 +0200 Subject: [PATCH 307/359] docs: update changelog (#7731) --- ui/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 8c9c12db4e..ed76338775 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Fix form validation in launch scan workflow. [(#7693)](https://github.com/prowler-cloud/prowler/pull/7693) - Moved ProviderType to a shared types file and replaced all occurrences across the codebase. [(#7710)](https://github.com/prowler-cloud/prowler/pull/7710) +- Added filter to retrieve only connected providers on the scan page. [(#7723)](https://github.com/prowler-cloud/prowler/pull/7723) --- From 413b948ca019fd5f17db625e4ea15a118467be6f Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Tue, 13 May 2025 15:28:01 +0200 Subject: [PATCH 308/359] feat(github): add GitHub provider (#5787) Co-authored-by: MrCloudSec --- .github/workflows/sdk-pull-request.yml | 17 +- README.md | 1 + poetry.lock | 53 ++- prowler/CHANGELOG.md | 1 + prowler/__main__.py | 5 + prowler/compliance/github/__init__.py | 0 prowler/compliance/github/cis_1.0_github.json | 7 + prowler/config/config.py | 1 + prowler/config/github_mutelist_example.yaml | 17 + prowler/lib/check/check.py | 5 +- prowler/lib/check/models.py | 31 ++ prowler/lib/outputs/finding.py | 8 + prowler/lib/outputs/html/html.py | 60 ++- prowler/lib/outputs/outputs.py | 2 + prowler/lib/outputs/slack/slack.py | 6 +- prowler/lib/outputs/summary_table.py | 8 + prowler/providers/common/provider.py | 9 + prowler/providers/github/__init__.py | 0 .../providers/github/exceptions/__init__.py | 0 .../providers/github/exceptions/exceptions.py | 95 +++++ prowler/providers/github/github_provider.py | 360 ++++++++++++++++++ .../github/lib/arguments/__init__.py | 0 .../github/lib/arguments/arguments.py | 34 ++ .../providers/github/lib/mutelist/__init__.py | 0 .../providers/github/lib/mutelist/mutelist.py | 18 + .../providers/github/lib/service/__init__.py | 0 .../providers/github/lib/service/service.py | 41 ++ prowler/providers/github/models.py | 42 ++ .../github/services/repository/__init__.py | 0 .../services/repository/repository_client.py | 4 + .../__init__.py | 0 ...y_public_has_securitymd_file.metadata.json | 30 ++ .../repository_public_has_securitymd_file.py | 42 ++ .../services/repository/repository_service.py | 45 +++ pyproject.toml | 1 + tests/lib/outputs/ocsf/ocsf_test.py | 5 +- tests/providers/github/github_fixtures.py | 37 ++ .../providers/github/github_provider_test.py | 137 +++++++ .../mutelist/fixtures/github_mutelist.yaml | 17 + .../lib/mutelist/github_mutelist_test.py | 100 +++++ ...ository_public_has_securitymd_file_test.py | 104 +++++ .../repository/repository_service_test.py | 41 ++ 42 files changed, 1371 insertions(+), 13 deletions(-) create mode 100644 prowler/compliance/github/__init__.py create mode 100644 prowler/compliance/github/cis_1.0_github.json create mode 100644 prowler/config/github_mutelist_example.yaml create mode 100644 prowler/providers/github/__init__.py create mode 100644 prowler/providers/github/exceptions/__init__.py create mode 100644 prowler/providers/github/exceptions/exceptions.py create mode 100644 prowler/providers/github/github_provider.py create mode 100644 prowler/providers/github/lib/arguments/__init__.py create mode 100644 prowler/providers/github/lib/arguments/arguments.py create mode 100644 prowler/providers/github/lib/mutelist/__init__.py create mode 100644 prowler/providers/github/lib/mutelist/mutelist.py create mode 100644 prowler/providers/github/lib/service/__init__.py create mode 100644 prowler/providers/github/lib/service/service.py create mode 100644 prowler/providers/github/models.py create mode 100644 prowler/providers/github/services/repository/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_client.py create mode 100644 prowler/providers/github/services/repository/repository_public_has_securitymd_file/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py create mode 100644 prowler/providers/github/services/repository/repository_service.py create mode 100644 tests/providers/github/github_fixtures.py create mode 100644 tests/providers/github/github_provider_test.py create mode 100644 tests/providers/github/lib/mutelist/fixtures/github_mutelist.yaml create mode 100644 tests/providers/github/lib/mutelist/github_mutelist_test.py create mode 100644 tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py create mode 100644 tests/providers/github/services/repository/repository_service_test.py diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml index 5249515f3c..1fa3e9c592 100644 --- a/.github/workflows/sdk-pull-request.yml +++ b/.github/workflows/sdk-pull-request.yml @@ -167,6 +167,21 @@ jobs: run: | poetry run pytest -n auto --cov=./prowler/providers/kubernetes --cov-report=xml:kubernetes_coverage.xml tests/providers/kubernetes + # Test GitHub + - name: GitHub - Check if any file has changed + id: github-changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + ./prowler/providers/github/** + ./tests/providers/github/** + .poetry.lock + + - name: GitHub - Test + if: steps.github-changed-files.outputs.any_changed == 'true' + run: | + poetry run pytest -n auto --cov=./prowler/providers/github --cov-report=xml:github_coverage.xml tests/providers/github + # Test NHN - name: NHN - Check if any file has changed id: nhn-changed-files @@ -216,4 +231,4 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: flags: prowler - files: ./aws_coverage.xml,./azure_coverage.xml,./gcp_coverage.xml,./kubernetes_coverage.xml,./nhn_coverage.xml,./m365_coverage.xml,./lib_coverage.xml,./config_coverage.xml + files: ./aws_coverage.xml,./azure_coverage.xml,./gcp_coverage.xml,./kubernetes_coverage.xml,./github_coverage.xml,./nhn_coverage.xml,./m365_coverage.xml,./lib_coverage.xml,./config_coverage.xml diff --git a/README.md b/README.md index 13c10cdd1c..5e20971be0 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ prowler dashboard | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | +| GitHub | 1 | 1 | 1 | 0 | | M365 | 44 | 2 | 2 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | diff --git a/poetry.lock b/poetry.lock index 98d30fac59..2734a604dd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -884,7 +884,6 @@ description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" groups = ["main", "dev"] -markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -954,6 +953,7 @@ files = [ {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] +markers = {dev = "platform_python_implementation != \"PyPy\""} [package.dependencies] pycparser = "*" @@ -3751,11 +3751,11 @@ description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main", "dev"] -markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +markers = {dev = "platform_python_implementation != \"PyPy\""} [[package]] name = "pydantic" @@ -3836,6 +3836,26 @@ files = [ {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] +[[package]] +name = "pygithub" +version = "2.5.0" +description = "Use the full Github API v3" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "PyGithub-2.5.0-py3-none-any.whl", hash = "sha256:b0b635999a658ab8e08720bdd3318893ff20e2275f6446fcf35bf3f44f2c0fd2"}, + {file = "pygithub-2.5.0.tar.gz", hash = "sha256:e1613ac508a9be710920d26eb18b1905ebd9926aa49398e88151c1b526aad3cf"}, +] + +[package.dependencies] +Deprecated = "*" +pyjwt = {version = ">=2.4.0", extras = ["crypto"]} +pynacl = ">=1.4.0" +requests = ">=2.14.0" +typing-extensions = ">=4.0.0" +urllib3 = ">=1.26.0" + [[package]] name = "pygments" version = "2.19.1" @@ -3922,6 +3942,33 @@ pyyaml = "*" [package.extras] extra = ["pygments (>=2.19.1)"] +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + [[package]] name = "pyparsing" version = "3.2.3" @@ -5407,4 +5454,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "cc15c8ee6b064b3fda85177c0f1c24a57880c401682fe62daefc2d0f4043150a" +content-hash = "f504af1d00a1da9dd65269509daf32f919c13be6c46f25cd9ef9bfba6b9c9a07" diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 95d593eae7..d147982f4d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update the compliance list supported for each provider from docs. [(#7694)](https://github.com/prowler-cloud/prowler/pull/7694) - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) +- Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) diff --git a/prowler/__main__.py b/prowler/__main__.py index 590f3e3bdb..95b08d6a15 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -96,6 +96,7 @@ from prowler.providers.azure.models import AzureOutputOptions from prowler.providers.common.provider import Provider from prowler.providers.common.quick_inventory import run_provider_quick_inventory from prowler.providers.gcp.models import GCPOutputOptions +from prowler.providers.github.models import GithubOutputOptions from prowler.providers.kubernetes.models import KubernetesOutputOptions from prowler.providers.m365.models import M365OutputOptions from prowler.providers.nhn.models import NHNOutputOptions @@ -280,6 +281,10 @@ def prowler(): output_options = KubernetesOutputOptions( args, bulk_checks_metadata, global_provider.identity ) + elif provider == "github": + output_options = GithubOutputOptions( + args, bulk_checks_metadata, global_provider.identity + ) elif provider == "m365": output_options = M365OutputOptions( args, bulk_checks_metadata, global_provider.identity diff --git a/prowler/compliance/github/__init__.py b/prowler/compliance/github/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/compliance/github/cis_1.0_github.json b/prowler/compliance/github/cis_1.0_github.json new file mode 100644 index 0000000000..f5431f2d44 --- /dev/null +++ b/prowler/compliance/github/cis_1.0_github.json @@ -0,0 +1,7 @@ +{ + "Framework": "CIS", + "Version": "1.0", + "Provider": "Github", + "Description": "This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for securing the Software Supply Chain.", + "Requirements": [] +} diff --git a/prowler/config/config.py b/prowler/config/config.py index 41d6e3e842..51f52ae3ca 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -29,6 +29,7 @@ class Provider(str, Enum): AZURE = "azure" KUBERNETES = "kubernetes" M365 = "m365" + GITHUB = "github" NHN = "nhn" diff --git a/prowler/config/github_mutelist_example.yaml b/prowler/config/github_mutelist_example.yaml new file mode 100644 index 0000000000..591dbed772 --- /dev/null +++ b/prowler/config/github_mutelist_example.yaml @@ -0,0 +1,17 @@ +### Account, Check and/or Region can be * to apply for all the cases. +### Account == +### Resources and tags are lists that can have either Regex or Keywords. +### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together. +### Use an alternation Regex to match one of multiple tags with "ORed" logic. +### For each check you can except Accounts, Regions, Resources and/or Tags. +########################### MUTELIST EXAMPLE ########################### +Mutelist: + Accounts: + "account_1": + Checks: + "repository_public_has_securitymd_file": + Regions: + - "*" + Resources: + - "resource_1" + - "resource_2" diff --git a/prowler/lib/check/check.py b/prowler/lib/check/check.py index 9ed70a22cd..bce9db8378 100644 --- a/prowler/lib/check/check.py +++ b/prowler/lib/check/check.py @@ -631,7 +631,10 @@ def execute( ) elif global_provider.type == "kubernetes": is_finding_muted_args["cluster"] = global_provider.identity.cluster - + elif global_provider.type == "github": + is_finding_muted_args["account_name"] = ( + global_provider.identity.account_name + ) for finding in check_findings: is_finding_muted_args["finding"] = finding finding.muted = global_provider.mutelist.is_finding_muted( diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index 4a729024f4..5e240f74cc 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -542,6 +542,37 @@ class Check_Report_Kubernetes(Check_Report): self.namespace = "cluster-wide" +@dataclass +class CheckReportGithub(Check_Report): + """Contains the GitHub Check's finding information.""" + + resource_name: str + resource_id: str + repository: str + + def __init__( + self, + metadata: Dict, + resource: Any, + resource_name: str = None, + resource_id: str = None, + repository: str = None, + ) -> None: + """Initialize the GitHub Check's finding information. + + Args: + metadata: The metadata of the check. + resource: Basic information about the resource. Defaults to None. + resource_name: The name of the resource related with the finding. + resource_id: The id of the resource related with the finding. + repository: The repository of the resource related with the finding. + """ + super().__init__(metadata, resource) + self.resource_name = resource_name or getattr(resource, "name", "") + self.resource_id = resource_id or getattr(resource, "id", "") + self.repository = repository or getattr(resource, "repository", "") + + @dataclass class CheckReportM365(Check_Report): """Contains the M365 Check's finding information.""" diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index f8aab16555..b7547da815 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -245,6 +245,14 @@ class Finding(BaseModel): ) output_data["region"] = f"namespace: {check_output.namespace}" + elif provider.type == "github": + output_data["auth_method"] = provider.auth_method + output_data["resource_name"] = check_output.resource_name + output_data["resource_uid"] = check_output.resource_id + output_data["account_name"] = provider.identity.account_name + output_data["account_uid"] = provider.identity.account_id + output_data["region"] = check_output.repository + elif provider.type == "m365": output_data["auth_method"] = ( f"{provider.identity.identity_type}: {provider.identity.identity_id}" diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index cb462396e6..f775a00d3d 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -544,11 +544,55 @@ class HTML(Output): ) return "" + @staticmethod + def get_github_assessment_summary(provider: Provider) -> str: + """ + get_github_assessment_summary gets the HTML assessment summary for the provider + + Args: + provider (Provider): the provider object + + Returns: + str: the HTML assessment summary + """ + try: + return f""" +

    +
    +
    + GitHub Assessment Summary +
    +
      +
    • + GitHub account: {provider.identity.account_name} +
    • +
    +
    +
    +
    +
    +
    + GitHub Credentials +
    +
      +
    • + GitHub authentication method: {provider.auth_method} +
    • +
    +
    +
    """ + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) + return "" + @staticmethod def get_m365_assessment_summary(provider: Provider) -> str: """ get_m365_assessment_summary gets the HTML assessment summary for the provider - Args: provider (Provider): the provider object @@ -564,7 +608,9 @@ class HTML(Output):
    • - M365 Tenant Domain: {provider.identity.tenant_domain} + M365 Tenant Domain: { + provider.identity.tenant_domain + }
    """ @@ -654,6 +705,7 @@ class HTML(Output): # It is not pretty but useful # AWS_provider --> aws # GCP_provider --> gcp + # GitHub_provider --> github # Azure_provider --> azure # Kubernetes_provider --> kubernetes diff --git a/prowler/lib/outputs/outputs.py b/prowler/lib/outputs/outputs.py index bb635510ac..adada2f513 100644 --- a/prowler/lib/outputs/outputs.py +++ b/prowler/lib/outputs/outputs.py @@ -16,6 +16,8 @@ def stdout_report(finding, color, verbose, status, fix): details = finding.location.lower() if finding.check_metadata.Provider == "kubernetes": details = finding.namespace.lower() + if finding.check_metadata.Provider == "github": + details = finding.repository if finding.check_metadata.Provider == "m365": details = finding.location if finding.check_metadata.Provider == "nhn": diff --git a/prowler/lib/outputs/slack/slack.py b/prowler/lib/outputs/slack/slack.py index 24fcc646ae..1b1773dc92 100644 --- a/prowler/lib/outputs/slack/slack.py +++ b/prowler/lib/outputs/slack/slack.py @@ -71,7 +71,7 @@ class Slack: - logo (str): The logo URL associated with the provider type. """ - # TODO: support kubernetes + # TODO: support kubernetes, m365, github try: identity = "" logo = aws_logo @@ -125,7 +125,7 @@ class Slack: "type": "section", "text": { "type": "mrkdwn", - "text": f"\n:white_check_mark: *{stats['total_pass']} Passed findings* ({round(stats['total_pass'] / stats['findings_count'] * 100 , 2)}%)\n", + "text": f"\n:white_check_mark: *{stats['total_pass']} Passed findings* ({round(stats['total_pass'] / stats['findings_count'] * 100, 2)}%)\n", }, }, { @@ -145,7 +145,7 @@ class Slack: "type": "section", "text": { "type": "mrkdwn", - "text": f"\n:x: *{stats['total_fail']} Failed findings* ({round(stats['total_fail'] / stats['findings_count'] * 100 , 2)}%)\n ", + "text": f"\n:x: *{stats['total_fail']} Failed findings* ({round(stats['total_fail'] / stats['findings_count'] * 100, 2)}%)\n ", }, }, { diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index 8d8dbc0e95..b1d9c7b8c1 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -11,6 +11,7 @@ from prowler.config.config import ( orange_color, ) from prowler.lib.logger import logger +from prowler.providers.github.models import GithubAppIdentityInfo, GithubIdentityInfo def display_summary_table( @@ -40,6 +41,13 @@ def display_summary_table( elif provider.type == "kubernetes": entity_type = "Context" audited_entities = provider.identity.context + elif provider.type == "github": + if isinstance(provider.identity, GithubIdentityInfo): + entity_type = "User Name" + audited_entities = provider.identity.account_name + elif isinstance(provider.identity, GithubAppIdentityInfo): + entity_type = "App ID" + audited_entities = provider.identity.app_id elif provider.type == "m365": entity_type = "Tenant Domain" audited_entities = provider.identity.tenant_domain diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 118346d6b5..9c97d63fbc 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -234,6 +234,15 @@ class Provider(ABC): mutelist_path=arguments.mutelist_file, fixer_config=fixer_config, ) + elif "github" in provider_class_name.lower(): + provider_class( + personal_access_token=arguments.personal_access_token, + oauth_app_token=arguments.oauth_app_token, + github_app_key=arguments.github_app_key, + github_app_id=arguments.github_app_id, + mutelist_path=arguments.mutelist_file, + config_path=arguments.config_file, + ) except TypeError as error: logger.critical( diff --git a/prowler/providers/github/__init__.py b/prowler/providers/github/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/exceptions/__init__.py b/prowler/providers/github/exceptions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/exceptions/exceptions.py b/prowler/providers/github/exceptions/exceptions.py new file mode 100644 index 0000000000..f7058d96ea --- /dev/null +++ b/prowler/providers/github/exceptions/exceptions.py @@ -0,0 +1,95 @@ +from prowler.exceptions.exceptions import ProwlerException + + +# Exceptions codes from 5000 to 5999 are reserved for Github exceptions +class GithubBaseException(ProwlerException): + """Base class for Github Errors.""" + + GITHUB_ERROR_CODES = { + (5000, "GithubEnvironmentVariableError"): { + "message": "Github environment variable error", + "remediation": "Check the Github environment variables and ensure they are properly set.", + }, + (5001, "GithubNonExistentTokenError"): { + "message": "A Github token is required to authenticate against Github", + "remediation": "Check the Github token and ensure it is properly set up.", + }, + (5002, "GithubInvalidTokenError"): { + "message": "Github token provided is not valid", + "remediation": "Check the Github token and ensure it is valid.", + }, + (5003, "GithubSetUpSessionError"): { + "message": "Error setting up session", + "remediation": "Check the session setup and ensure it is properly set up.", + }, + (5004, "GithubSetUpIdentityError"): { + "message": "Github identity setup error due to bad credentials", + "remediation": "Check credentials and ensure they are properly set up for Github and the identity provider.", + }, + (5005, "GithubInvalidCredentialsError"): { + "message": "Github invalid App Key or App ID for GitHub APP login", + "remediation": "Check user and password and ensure they are properly set up as in your Github account.", + }, + } + + def __init__(self, code, file=None, original_exception=None, message=None): + provider = "Github" + error_info = self.GITHUB_ERROR_CODES.get((code, self.__class__.__name__)) + if message: + error_info["message"] = message + super().__init__( + code=code, + source=provider, + file=file, + original_exception=original_exception, + error_info=error_info, + ) + + +class GithubCredentialsError(GithubBaseException): + """Base class for Github credentials errors.""" + + def __init__(self, code, file=None, original_exception=None, message=None): + super().__init__(code, file, original_exception, message) + + +class GithubEnvironmentVariableError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5000, file=file, original_exception=original_exception, message=message + ) + + +class GithubNonExistentTokenError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5001, file=file, original_exception=original_exception, message=message + ) + + +class GithubInvalidTokenError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5002, file=file, original_exception=original_exception, message=message + ) + + +class GithubSetUpSessionError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5003, file=file, original_exception=original_exception, message=message + ) + + +class GithubSetUpIdentityError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5004, file=file, original_exception=original_exception, message=message + ) + + +class GithubInvalidCredentialsError(GithubCredentialsError): + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 5005, file=file, original_exception=original_exception, message=message + ) diff --git a/prowler/providers/github/github_provider.py b/prowler/providers/github/github_provider.py new file mode 100644 index 0000000000..000f0e40d5 --- /dev/null +++ b/prowler/providers/github/github_provider.py @@ -0,0 +1,360 @@ +import os +from os import environ +from typing import Union + +from colorama import Fore, Style +from github import Auth, Github, GithubIntegration + +from prowler.config.config import ( + default_config_file_path, + get_default_mute_file_path, + load_and_validate_config_file, +) +from prowler.lib.logger import logger +from prowler.lib.mutelist.mutelist import Mutelist +from prowler.lib.utils.utils import print_boxes +from prowler.providers.common.models import Audit_Metadata +from prowler.providers.common.provider import Provider +from prowler.providers.github.exceptions.exceptions import ( + GithubEnvironmentVariableError, + GithubInvalidCredentialsError, + GithubInvalidTokenError, + GithubSetUpIdentityError, + GithubSetUpSessionError, +) +from prowler.providers.github.lib.mutelist.mutelist import GithubMutelist +from prowler.providers.github.models import ( + GithubAppIdentityInfo, + GithubIdentityInfo, + GithubSession, +) + + +def format_rsa_key(key: str) -> str: + """ + Format an RSA private key by adding line breaks to the key body. + This function takes an RSA private key in PEM format as input and formats it by inserting line breaks every 64 characters in the key body. This formatting is necessary for the GitHub SDK Parser to correctly process the key. + Args: + key (str): The RSA private key in PEM format as a string. The key should start with "-----BEGIN RSA PRIVATE KEY-----" and end with "-----END RSA PRIVATE KEY-----". + Returns: + str: The formatted RSA private key with line breaks added to the key body. If the input key does not have the correct headers, it is returned unchanged. + Example: + >>> key = "-----BEGIN RSA PRIVATE KEY-----XXXXXXXXXXXXX...-----END RSA PRIVATE KEY-----" + >>> formatted_key = format_rsa_key(key) + >>> print(formatted_key) + -----BEGIN RSA PRIVATE KEY----- + XXXXXXXXXXXXX... + -----END RSA PRIVATE KEY----- + + """ + if ( + key.startswith("-----BEGIN RSA PRIVATE KEY-----") + and key.endswith("-----END RSA PRIVATE KEY-----") + and "\n" not in key + ): + # Extract the key body (excluding the headers) + key_body = key[ + len("-----BEGIN RSA PRIVATE KEY-----") : len(key) + - len("-----END RSA PRIVATE KEY-----") + ].strip() + # Add line breaks to the body + formatted_key_body = "\n".join( + [key_body[i : i + 64] for i in range(0, len(key_body), 64)] + ) + # Reconstruct the key with headers and formatted body + return f"-----BEGIN RSA PRIVATE KEY-----\n{formatted_key_body}\n-----END RSA PRIVATE KEY-----" + return key + + +class GithubProvider(Provider): + """ + GitHub Provider class + + This class is responsible for setting up the GitHub provider, including the session, identity, audit configuration, fixer configuration, and mutelist. + + Attributes: + _type (str): The type of the provider. + _auth_method (str): The authentication method used by the provider. + _session (GithubSession): The session object for the provider. + _identity (GithubIdentityInfo): The identity information for the provider. + _audit_config (dict): The audit configuration for the provider. + _fixer_config (dict): The fixer configuration for the provider. + _mutelist (Mutelist): The mutelist for the provider. + audit_metadata (Audit_Metadata): The audit metadata for the provider. + """ + + _type: str = "github" + _auth_method: str = None + _session: GithubSession + _identity: GithubIdentityInfo + _audit_config: dict + _mutelist: Mutelist + audit_metadata: Audit_Metadata + + def __init__( + self, + # Authentication credentials + personal_access_token: str = "", + oauth_app_token: str = "", + github_app_key: str = "", + github_app_id: int = 0, + # Provider configuration + config_path: str = None, + config_content: dict = None, + fixer_config: dict = {}, + mutelist_path: str = None, + mutelist_content: dict = None, + ): + """ + GitHub Provider constructor + + Args: + personal_access_token (str): GitHub personal access token. + oauth_app_token (str): GitHub OAuth App token. + github_app_key (str): GitHub App key. + github_app_id (int): GitHub App ID. + config_path (str): Path to the audit configuration file. + config_content (dict): Audit configuration content. + fixer_config (dict): Fixer configuration content. + mutelist_path (str): Path to the mutelist file. + mutelist_content (dict): Mutelist content. + """ + logger.info("Instantiating GitHub Provider...") + + self._session = self.setup_session( + personal_access_token, + oauth_app_token, + github_app_id, + github_app_key, + ) + + self._identity = self.setup_identity() + + # Audit Config + if config_content: + self._audit_config = config_content + else: + if not config_path: + config_path = default_config_file_path + self._audit_config = load_and_validate_config_file(self._type, config_path) + + # Fixer Config + self._fixer_config = fixer_config + + # Mutelist + if mutelist_content: + self._mutelist = GithubMutelist( + mutelist_content=mutelist_content, + ) + else: + if not mutelist_path: + mutelist_path = get_default_mute_file_path(self.type) + self._mutelist = GithubMutelist( + mutelist_path=mutelist_path, + ) + Provider.set_global_provider(self) + + @property + def auth_method(self): + """Returns the authentication method for the GitHub provider.""" + return self._auth_method + + @property + def pat(self): + """Returns the personal access token for the GitHub provider.""" + return self._pat + + @property + def session(self): + """Returns the session object for the GitHub provider.""" + return self._session + + @property + def identity(self): + """Returns the identity information for the GitHub provider.""" + return self._identity + + @property + def type(self): + """Returns the type of the GitHub provider.""" + return self._type + + @property + def audit_config(self): + return self._audit_config + + @property + def fixer_config(self): + return self._fixer_config + + @property + def mutelist(self) -> GithubMutelist: + """ + mutelist method returns the provider's mutelist. + """ + return self._mutelist + + def setup_session( + self, + personal_access_token: str = None, + oauth_app_token: str = None, + github_app_id: int = 0, + github_app_key: str = None, + ) -> GithubSession: + """ + Returns the GitHub headers responsible authenticating API calls. + + Args: + personal_access_token (str): GitHub personal access token. + oauth_app_token (str): GitHub OAuth App token. + github_app_id (int): GitHub App ID. + github_app_key (str): GitHub App key. + + Returns: + GithubSession: Authenticated session token for API requests. + """ + + session_token = "" + app_key = "" + app_id = 0 + + try: + # Ensure that at least one authentication method is selected. Default to environment variable for PAT if none is provided. + if personal_access_token: + session_token = personal_access_token + self._auth_method = "Personal Access Token" + + elif oauth_app_token: + session_token = oauth_app_token + self._auth_method = "OAuth App Token" + + elif github_app_id and github_app_key: + app_id = github_app_id + with open(github_app_key, "r") as rsa_key: + app_key = rsa_key.read() + + self._auth_method = "GitHub App Token" + + else: + # PAT + logger.info( + "Looking for GITHUB_PERSONAL_ACCESS_TOKEN environment variable as user has not provided any token...." + ) + session_token = environ.get("GITHUB_PERSONAL_ACCESS_TOKEN", "") + if session_token: + self._auth_method = "Environment Variable for Personal Access Token" + + if not session_token: + # OAUTH + logger.info( + "Looking for GITHUB_OAUTH_TOKEN environment variable as user has not provided any token...." + ) + session_token = environ.get("GITHUB_OAUTH_APP_TOKEN", "") + if session_token: + self._auth_method = "Environment Variable for OAuth App Token" + + if not session_token: + # APP + logger.info( + "Looking for GITHUB_APP_ID and GITHUB_APP_KEY environment variables as user has not provided any token...." + ) + app_id = environ.get("GITHUB_APP_ID", "") + app_key = format_rsa_key(environ.get(r"GITHUB_APP_KEY", "")) + + if app_id and app_key: + self._auth_method = ( + "Environment Variables for GitHub App Key and ID" + ) + + if not self._auth_method: + raise GithubEnvironmentVariableError( + file=os.path.basename(__file__), + message="No authentication method selected and not environment variables were found.", + ) + + credentials = GithubSession( + token=session_token, + key=app_key, + id=app_id, + ) + + return credentials + + except Exception as error: + logger.critical( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) + raise GithubSetUpSessionError( + original_exception=error, + ) + + def setup_identity( + self, + ) -> Union[GithubIdentityInfo, GithubAppIdentityInfo]: + """ + Returns the GitHub identity information + + Returns: + GithubIdentityInfo | GithubAppIdentityInfo: An instance of GithubIdentityInfo or GithubAppIdentityInfo containing the identity information. + """ + credentials = self.session + + try: + if credentials.token: + auth = Auth.Token(credentials.token) + g = Github(auth=auth) + try: + identity = GithubIdentityInfo( + account_id=g.get_user().id, + account_name=g.get_user().login, + account_url=g.get_user().url, + ) + return identity + + except Exception as error: + raise GithubInvalidTokenError( + original_exception=error, + ) + + elif credentials.id != 0 and credentials.key: + auth = Auth.AppAuth(credentials.id, credentials.key) + gi = GithubIntegration(auth=auth) + try: + identity = GithubAppIdentityInfo(app_id=gi.get_app().id) + return identity + + except Exception as error: + raise GithubInvalidCredentialsError( + original_exception=error, + ) + + except Exception as error: + logger.critical( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) + raise GithubSetUpIdentityError( + original_exception=error, + ) + + def print_credentials(self): + """ + Prints the GitHub credentials. + + Usage: + >>> self.print_credentials() + """ + if isinstance(self.identity, GithubIdentityInfo): + report_lines = [ + f"GitHub Account: {Fore.YELLOW}{self.identity.account_name}{Style.RESET_ALL}", + f"GitHub Account ID: {Fore.YELLOW}{self.identity.account_id}{Style.RESET_ALL}", + f"Authentication Method: {Fore.YELLOW}{self.auth_method}{Style.RESET_ALL}", + ] + elif isinstance(self.identity, GithubAppIdentityInfo): + report_lines = [ + f"GitHub App ID: {Fore.YELLOW}{self.identity.app_id}{Style.RESET_ALL}", + f"Authentication Method: {Fore.YELLOW}{self.auth_method}{Style.RESET_ALL}", + ] + report_title = ( + f"{Style.BRIGHT}Using the GitHub credentials below:{Style.RESET_ALL}" + ) + print_boxes(report_lines, report_title) diff --git a/prowler/providers/github/lib/arguments/__init__.py b/prowler/providers/github/lib/arguments/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/lib/arguments/arguments.py b/prowler/providers/github/lib/arguments/arguments.py new file mode 100644 index 0000000000..6e7598c8d7 --- /dev/null +++ b/prowler/providers/github/lib/arguments/arguments.py @@ -0,0 +1,34 @@ +def init_parser(self): + """Init the Github Provider CLI parser""" + github_parser = self.subparsers.add_parser( + "github", parents=[self.common_providers_parser], help="GitHub Provider" + ) + github_auth_subparser = github_parser.add_argument_group("Authentication Modes") + # Authentication Modes + github_auth_subparser.add_argument( + "--personal-access-token", + nargs="?", + help="Personal Access Token to log in against GitHub", + default=None, + ) + + github_auth_subparser.add_argument( + "--oauth-app-token", + nargs="?", + help="OAuth App Token to log in against GitHub", + default=None, + ) + + # GitHub App Authentication + github_auth_subparser.add_argument( + "--github-app-id", + nargs="?", + help="GitHub App ID to log in against GitHub", + default=None, + ) + github_auth_subparser.add_argument( + "--github-app-key", + nargs="?", + help="GitHub App Key Path to log in against GitHub", + default=None, + ) diff --git a/prowler/providers/github/lib/mutelist/__init__.py b/prowler/providers/github/lib/mutelist/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/lib/mutelist/mutelist.py b/prowler/providers/github/lib/mutelist/mutelist.py new file mode 100644 index 0000000000..207b54a52a --- /dev/null +++ b/prowler/providers/github/lib/mutelist/mutelist.py @@ -0,0 +1,18 @@ +from prowler.lib.check.models import CheckReportGithub +from prowler.lib.mutelist.mutelist import Mutelist +from prowler.lib.outputs.utils import unroll_dict, unroll_tags + + +class GithubMutelist(Mutelist): + def is_finding_muted( + self, + finding: CheckReportGithub, + account_name: str, + ) -> bool: + return self.is_muted( + account_name, + finding.check_metadata.CheckID, + "*", # TODO: Study regions in GitHub + finding.resource_name, + unroll_dict(unroll_tags(finding.resource_tags)), + ) diff --git a/prowler/providers/github/lib/service/__init__.py b/prowler/providers/github/lib/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/lib/service/service.py b/prowler/providers/github/lib/service/service.py new file mode 100644 index 0000000000..b9e4bf2974 --- /dev/null +++ b/prowler/providers/github/lib/service/service.py @@ -0,0 +1,41 @@ +from github import Auth, Github, GithubIntegration + +from prowler.lib.logger import logger +from prowler.providers.github.github_provider import GithubProvider + + +class GithubService: + def __init__( + self, + service: str, + provider: GithubProvider, + ): + self.clients = self.__set_clients__( + provider.session, + ) + + self.audit_config = provider.audit_config + self.fixer_config = provider.fixer_config + + def __set_clients__(self, session): + clients = [] + try: + if session.token: + auth = Auth.Token(session.token) + clients = [Github(auth=auth)] + + elif session.key and session.id: + auth = Auth.AppAuth( + session.id, + session.key, + ) + gi = GithubIntegration(auth=auth) + + for installation in gi.get_installations(): + clients.append(installation.get_github_for_installation()) + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return clients diff --git a/prowler/providers/github/models.py b/prowler/providers/github/models.py new file mode 100644 index 0000000000..a4fb2fdc36 --- /dev/null +++ b/prowler/providers/github/models.py @@ -0,0 +1,42 @@ +from pydantic import BaseModel + +from prowler.config.config import output_file_timestamp +from prowler.providers.common.models import ProviderOutputOptions + + +class GithubSession(BaseModel): + token: str + key: str + id: str + + +class GithubIdentityInfo(BaseModel): + account_id: str + account_name: str + account_url: str + + +class GithubAppIdentityInfo(BaseModel): + app_id: str + + +class GithubOutputOptions(ProviderOutputOptions): + def __init__(self, arguments, bulk_checks_metadata, identity): + # First call ProviderOutputOptions init + super().__init__(arguments, bulk_checks_metadata) + # TODO move the below if to ProviderOutputOptions + # Check if custom output filename was input, if not, set the default + if ( + not hasattr(arguments, "output_filename") + or arguments.output_filename is None + ): + if isinstance(identity, GithubIdentityInfo): + self.output_filename = ( + f"prowler-output-{identity.account_name}-{output_file_timestamp}" + ) + elif isinstance(identity, GithubAppIdentityInfo): + self.output_filename = ( + f"prowler-output-{identity.app_id}-{output_file_timestamp}" + ) + else: + self.output_filename = arguments.output_filename diff --git a/prowler/providers/github/services/repository/__init__.py b/prowler/providers/github/services/repository/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_client.py b/prowler/providers/github/services/repository/repository_client.py new file mode 100644 index 0000000000..3ea47cb952 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_client.py @@ -0,0 +1,4 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.github.services.repository.repository_service import Repository + +repository_client = Repository(Provider.get_global_provider()) diff --git a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/__init__.py b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json new file mode 100644 index 0000000000..69c9446aa7 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_public_has_securitymd_file", + "CheckTitle": "Check if public repositories have a SECURITY.md file", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "github:user-id:repository/repository-name", + "Severity": "low", + "ResourceType": "Other", + "Description": "Ensure that public repositories have a SECURITY.md file", + "Risk": "Not having a SECURITY.md file in a public repository may lead to security vulnerabilities being overlooked by users and contributors.", + "RelatedUrl": "https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Add a SECURITY.md file to the root of the repository. The file should contain information on how to report a security vulnerability, the security policy of the repository, and any other relevant information.", + "Url": "https://github.blog/changelog/2019-05-23-security-policy/" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py new file mode 100644 index 0000000000..342b8f5e9f --- /dev/null +++ b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_public_has_securitymd_file(Check): + """Check if a public repository has a SECURITY.md file + + This class verifies whether each public repository has a SECURITY.md file. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Public Has SECURITY.md File check + + Iterates over all public repositories and checks if they have a SECURITY.md file. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if not repo.private: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does have a SECURITY.md file." + ) + + if not repo.securitymd: + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does not have a SECURITY.md file." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py new file mode 100644 index 0000000000..f7c2c02760 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_service.py @@ -0,0 +1,45 @@ +from typing import Optional + +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.github.lib.service.service import GithubService + + +class Repository(GithubService): + def __init__(self, provider): + super().__init__(__class__.__name__, provider) + self.repositories = self._list_repositories() + + def _list_repositories(self): + logger.info("Repository - Listing Repositories...") + repos = {} + try: + for client in self.clients: + for repo in client.get_user().get_repos(): + try: + securitymd_exists = repo.get_contents("SECURITY.md") is not None + except Exception: + securitymd_exists = False + repos[repo.id] = Repo( + id=repo.id, + name=repo.name, + full_name=repo.full_name, + private=repo.private, + securitymd=securitymd_exists, + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return repos + + +class Repo(BaseModel): + """Model for Github Repository""" + + id: int + name: str + full_name: str + private: bool + securitymd: Optional[bool] = False diff --git a/pyproject.toml b/pyproject.toml index 1c1e3a49c7..b2e9b9feb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ dependencies = [ "pandas==2.2.3", "py-ocsf-models==0.3.1", "pydantic==1.10.21", + "pygithub==2.5.0", "python-dateutil (>=2.9.0.post0,<3.0.0)", "pytz==2025.1", "schema==0.7.7", diff --git a/tests/lib/outputs/ocsf/ocsf_test.py b/tests/lib/outputs/ocsf/ocsf_test.py index 4f761ff274..9f8d493069 100644 --- a/tests/lib/outputs/ocsf/ocsf_test.py +++ b/tests/lib/outputs/ocsf/ocsf_test.py @@ -328,7 +328,10 @@ class TestOCSF: assert isinstance(resource_details[0], ResourceDetails) assert resource_details[0].labels == ["Name:test", "Environment:dev"] assert resource_details[0].name == finding_output.resource_name - assert resource_details[0].uid == finding_output.resource_uid + assert resource_details[0].data == { + "details": finding_output.resource_details, + "metadata": {}, # TODO: add metadata to the resource details + } assert resource_details[0].type == finding_output.metadata.ResourceType assert resource_details[0].cloud_partition == finding_output.partition assert resource_details[0].region == finding_output.region diff --git a/tests/providers/github/github_fixtures.py b/tests/providers/github/github_fixtures.py new file mode 100644 index 0000000000..a848c9ed17 --- /dev/null +++ b/tests/providers/github/github_fixtures.py @@ -0,0 +1,37 @@ +from mock import MagicMock + +from prowler.providers.github.github_provider import GithubProvider +from prowler.providers.github.models import GithubIdentityInfo, GithubSession + +# GitHub Identity +ACCOUNT_NAME = "account-name" +ACCOUNT_ID = "account-id" +ACCOUNT_URL = "/user" + +# GitHub Credentials +PAT_TOKEN = "github-token" +OAUTH_TOKEN = "oauth-token" +APP_ID = "app-id" +APP_KEY = "app-key" + + +# Mocked GitHub Provider +def set_mocked_github_provider( + auth_method: str = "personal_access", + credentials: GithubSession = GithubSession(token=PAT_TOKEN, id=APP_ID, key=APP_KEY), + identity: GithubIdentityInfo = GithubIdentityInfo( + account_name=ACCOUNT_NAME, + account_id=ACCOUNT_ID, + account_url=ACCOUNT_URL, + ), + audit_config: dict = None, +) -> GithubProvider: + + provider = MagicMock() + provider.type = "github" + provider.auth_method = auth_method + provider.session = credentials + provider.identity = identity + provider.audit_config = audit_config + + return provider diff --git a/tests/providers/github/github_provider_test.py b/tests/providers/github/github_provider_test.py new file mode 100644 index 0000000000..30d770ef3b --- /dev/null +++ b/tests/providers/github/github_provider_test.py @@ -0,0 +1,137 @@ +from unittest.mock import patch + +from prowler.config.config import ( + default_fixer_config_file_path, + load_and_validate_config_file, +) +from prowler.providers.github.github_provider import GithubProvider +from prowler.providers.github.models import ( + GithubAppIdentityInfo, + GithubIdentityInfo, + GithubSession, +) +from tests.providers.github.github_fixtures import ( + ACCOUNT_ID, + ACCOUNT_NAME, + ACCOUNT_URL, + APP_ID, + APP_KEY, + OAUTH_TOKEN, + PAT_TOKEN, +) + + +class TestGitHubProvider: + def test_github_provider_PAT(self): + personal_access_token = PAT_TOKEN + oauth_app_token = None + github_app_id = None + github_app_key = None + fixer_config = load_and_validate_config_file( + "github", default_fixer_config_file_path + ) + + with ( + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_session", + return_value=GithubSession(token=PAT_TOKEN, id="", key=""), + ), + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_identity", + return_value=GithubIdentityInfo( + account_id=ACCOUNT_ID, + account_name=ACCOUNT_NAME, + account_url=ACCOUNT_URL, + ), + ), + ): + provider = GithubProvider( + personal_access_token, + oauth_app_token, + github_app_id, + github_app_key, + ) + + assert provider._type == "github" + assert provider.session == GithubSession(token=PAT_TOKEN, id="", key="") + assert provider.identity == GithubIdentityInfo( + account_name=ACCOUNT_NAME, + account_id=ACCOUNT_ID, + account_url=ACCOUNT_URL, + ) + assert provider._audit_config == {} + assert provider._fixer_config == fixer_config + + def test_github_provider_OAuth(self): + personal_access_token = None + oauth_app_token = OAUTH_TOKEN + github_app_id = None + github_app_key = None + fixer_config = load_and_validate_config_file( + "github", default_fixer_config_file_path + ) + + with ( + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_session", + return_value=GithubSession(token=OAUTH_TOKEN, id="", key=""), + ), + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_identity", + return_value=GithubIdentityInfo( + account_id=ACCOUNT_ID, + account_name=ACCOUNT_NAME, + account_url=ACCOUNT_URL, + ), + ), + ): + provider = GithubProvider( + personal_access_token, + oauth_app_token, + github_app_id, + github_app_key, + ) + + assert provider._type == "github" + assert provider.session == GithubSession(token=OAUTH_TOKEN, id="", key="") + assert provider.identity == GithubIdentityInfo( + account_name=ACCOUNT_NAME, + account_id=ACCOUNT_ID, + account_url=ACCOUNT_URL, + ) + assert provider._audit_config == {} + assert provider._fixer_config == fixer_config + + def test_github_provider_App(self): + personal_access_token = None + oauth_app_token = None + github_app_id = APP_ID + github_app_key = APP_KEY + fixer_config = load_and_validate_config_file( + "github", default_fixer_config_file_path + ) + + with ( + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_session", + return_value=GithubSession(token="", id=APP_ID, key=APP_KEY), + ), + patch( + "prowler.providers.github.github_provider.GithubProvider.setup_identity", + return_value=GithubAppIdentityInfo( + app_id=APP_ID, + ), + ), + ): + provider = GithubProvider( + personal_access_token, + oauth_app_token, + github_app_id, + github_app_key, + ) + + assert provider._type == "github" + assert provider.session == GithubSession(token="", id=APP_ID, key=APP_KEY) + assert provider.identity == GithubAppIdentityInfo(app_id=APP_ID) + assert provider._audit_config == {} + assert provider._fixer_config == fixer_config diff --git a/tests/providers/github/lib/mutelist/fixtures/github_mutelist.yaml b/tests/providers/github/lib/mutelist/fixtures/github_mutelist.yaml new file mode 100644 index 0000000000..591dbed772 --- /dev/null +++ b/tests/providers/github/lib/mutelist/fixtures/github_mutelist.yaml @@ -0,0 +1,17 @@ +### Account, Check and/or Region can be * to apply for all the cases. +### Account == +### Resources and tags are lists that can have either Regex or Keywords. +### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together. +### Use an alternation Regex to match one of multiple tags with "ORed" logic. +### For each check you can except Accounts, Regions, Resources and/or Tags. +########################### MUTELIST EXAMPLE ########################### +Mutelist: + Accounts: + "account_1": + Checks: + "repository_public_has_securitymd_file": + Regions: + - "*" + Resources: + - "resource_1" + - "resource_2" diff --git a/tests/providers/github/lib/mutelist/github_mutelist_test.py b/tests/providers/github/lib/mutelist/github_mutelist_test.py new file mode 100644 index 0000000000..8b8cc803fd --- /dev/null +++ b/tests/providers/github/lib/mutelist/github_mutelist_test.py @@ -0,0 +1,100 @@ +import yaml +from mock import MagicMock + +from prowler.providers.github.lib.mutelist.mutelist import GithubMutelist +from tests.lib.outputs.fixtures.fixtures import generate_finding_output + +MUTELIST_FIXTURE_PATH = ( + "tests/providers/github/lib/mutelist/fixtures/github_mutelist.yaml" +) + + +class TestGithubMutelist: + def test_get_mutelist_file_from_local_file(self): + mutelist = GithubMutelist(mutelist_path=MUTELIST_FIXTURE_PATH) + + with open(MUTELIST_FIXTURE_PATH) as f: + mutelist_fixture = yaml.safe_load(f)["Mutelist"] + + assert mutelist.mutelist == mutelist_fixture + assert mutelist.mutelist_file_path == MUTELIST_FIXTURE_PATH + + def test_get_mutelist_file_from_local_file_non_existent(self): + mutelist_path = "tests/lib/mutelist/fixtures/not_present" + mutelist = GithubMutelist(mutelist_path=mutelist_path) + + assert mutelist.mutelist == {} + assert mutelist.mutelist_file_path == mutelist_path + + def test_validate_mutelist_not_valid_key(self): + mutelist_path = MUTELIST_FIXTURE_PATH + with open(mutelist_path) as f: + mutelist_fixture = yaml.safe_load(f)["Mutelist"] + + mutelist_fixture["Accounts1"] = mutelist_fixture["Accounts"] + del mutelist_fixture["Accounts"] + + mutelist = GithubMutelist(mutelist_content=mutelist_fixture) + + assert not mutelist.validate_mutelist() + assert mutelist.mutelist == {} + assert mutelist.mutelist_file_path is None + + def test_is_finding_muted(self): + # Mutelist + mutelist_content = { + "Accounts": { + "account_1": { + "Checks": { + "check_test": { + "Regions": ["*"], + "Resources": ["test_resource"], + } + } + } + } + } + + mutelist = GithubMutelist(mutelist_content=mutelist_content) + + finding = MagicMock() + finding.check_metadata = MagicMock() + finding.check_metadata.CheckID = "check_test" + finding.status = "FAIL" + finding.resource_name = "test_resource" + finding.account_name = "account_1" + finding.location = "test-location" + finding.resource_tags = [] + + assert mutelist.is_finding_muted(finding, finding.account_name) + + def test_mute_finding(self): + # Mutelist + mutelist_content = { + "Accounts": { + "account_1": { + "Checks": { + "check_test": { + "Regions": ["*"], + "Resources": ["test_resource"], + } + } + } + } + } + + mutelist = GithubMutelist(mutelist_content=mutelist_content) + + finding_1 = generate_finding_output( + check_id="check_test", + status="FAIL", + account_uid="account_1", + resource_uid="test_resource", + resource_tags=[], + ) + + muted_finding = mutelist.mute_finding(finding=finding_1) + + assert muted_finding.status == "MUTED" + assert muted_finding.muted + assert muted_finding.raw["status"] == "FAIL" diff --git a/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py b/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py new file mode 100644 index 0000000000..ccbf02c075 --- /dev/null +++ b/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py @@ -0,0 +1,104 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_public_has_securitymd_file_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import ( + repository_public_has_securitymd_file, + ) + + check = repository_public_has_securitymd_file() + result = check.execute() + assert len(result) == 0 + + def test_one_repository_no_securitymd(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import ( + repository_public_has_securitymd_file, + ) + + check = repository_public_has_securitymd_file() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not have a SECURITY.md file." + ) + + def test_one_repository_securitymd(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import ( + repository_public_has_securitymd_file, + ) + + check = repository_public_has_securitymd_file() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does have a SECURITY.md file." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py new file mode 100644 index 0000000000..a375b5c62c --- /dev/null +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -0,0 +1,41 @@ +from unittest.mock import patch + +from prowler.providers.github.services.repository.repository_service import ( + Repo, + Repository, +) +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +def mock_list_repositories(_): + return { + 1: Repo( + id=1, + name="repo1", + full_name="account-name/repo1", + private=False, + securitymd=False, + ), + } + + +@patch( + "prowler.providers.github.services.repository.repository_service.Repository._list_repositories", + new=mock_list_repositories, +) +class Test_Repository_Service: + def test_get_client(self): + repository_service = Repository(set_mocked_github_provider()) + assert repository_service.clients[0].__class__.__name__ == "Github" + + def test_get_service(self): + repository_service = Repository(set_mocked_github_provider()) + assert repository_service.__class__.__name__ == "Repository" + + def test_list_repositories(self): + repository_service = Repository(set_mocked_github_provider()) + assert len(repository_service.repositories) == 1 + assert repository_service.repositories[1].name == "repo1" + assert repository_service.repositories[1].full_name == "account-name/repo1" + assert repository_service.repositories[1].private is False + assert repository_service.repositories[1].securitymd is False From 2ee62cca8eab2f2480284b9d3a0cd084cf3a6e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Wed, 14 May 2025 08:39:49 +0200 Subject: [PATCH 309/359] chore: add ref on checkout step (#7740) --- .github/workflows/pull-request-merged.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pull-request-merged.yml index b4ad343a4e..090950f79b 100644 --- a/.github/workflows/pull-request-merged.yml +++ b/.github/workflows/pull-request-merged.yml @@ -12,6 +12,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.pull_request.merge_commit_sha }} - name: Set short git commit SHA id: vars From deec9efa97bce5c145a6a698111122feb55f9b80 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 14 May 2025 13:15:01 +0545 Subject: [PATCH 310/359] feat(ui): Add AWS CloudFormation Quick Link to deploy the IAM Role (#7735) --- ui/CHANGELOG.md | 1 + .../workflow/credentials-role-helper.tsx | 46 +++++++++++++++---- .../workflow/forms/via-role/aws-role-form.tsx | 7 +-- .../workflow/provider-title-docs.tsx | 36 +-------------- ui/lib/external-urls.ts | 45 ++++++++++++++++++ ui/lib/index.ts | 1 + 6 files changed, 89 insertions(+), 47 deletions(-) create mode 100644 ui/lib/external-urls.ts diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index ed76338775..3dc0f8ba35 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Add a new chart to show the split between passed and failed findings. [(#7680)](https://github.com/prowler-cloud/prowler/pull/7680) - Added `Accordion` component. [(#7700)](https://github.com/prowler-cloud/prowler/pull/7700) +- Added an AWS CloudFormation Quick Link to the IAM Role credentials step [(#7735)](https://github.com/prowler-cloud/prowler/pull/7735) ### 🐞 Fixes diff --git a/ui/components/providers/workflow/credentials-role-helper.tsx b/ui/components/providers/workflow/credentials-role-helper.tsx index 896fd657a7..855a3e6fab 100644 --- a/ui/components/providers/workflow/credentials-role-helper.tsx +++ b/ui/components/providers/workflow/credentials-role-helper.tsx @@ -1,9 +1,11 @@ "use client"; import { Snippet } from "@nextui-org/react"; -import Link from "next/link"; import { useSession } from "next-auth/react"; +import { CustomButton } from "@/components/ui/custom"; +import { getAWSCredentialsTemplateLinks } from "@/lib"; + export const CredentialsRoleHelper = () => { const { data: session } = useSession(); @@ -12,24 +14,50 @@ export const CredentialsRoleHelper = () => {

    A new read-only IAM role must be manually created. +

    + + + Use the following AWS CloudFormation Quick Link to deploy the IAM Role + + +
    +
    + + or + +
    +
    +

    Use one of the following templates to create the IAM role:

    +
    - CloudFormation Template - - + Terraform Code - +
    +

    The External ID will also be required:

    diff --git a/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx b/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx index 7ed4cd9438..c9994284d9 100644 --- a/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx +++ b/ui/components/providers/workflow/forms/via-role/aws-role-form.tsx @@ -1,4 +1,4 @@ -import { Select, SelectItem, Spacer } from "@nextui-org/react"; +import { Divider, Select, SelectItem, Spacer } from "@nextui-org/react"; import { Control, UseFormSetValue, useWatch } from "react-hook-form"; import { CustomInput } from "@/components/ui/custom"; @@ -89,10 +89,11 @@ export const AWSCredentialsRoleForm = ({ /> )} + + Assume Role - Assume Role { - const getProviderHelpText = (provider: string) => { - switch (provider) { - case "aws": - return { - text: "Need help connecting your AWS account?", - link: "https://goto.prowler.com/provider-aws", - }; - case "azure": - return { - text: "Need help connecting your Azure subscription?", - link: "https://goto.prowler.com/provider-azure", - }; - case "m365": - return { - text: "Need help connecting your Microsoft 365 account?", - link: "https://goto.prowler.com/provider-m365", - }; - case "gcp": - return { - text: "Need help connecting your GCP project?", - link: "https://goto.prowler.com/provider-gcp", - }; - case "kubernetes": - return { - text: "Need help connecting your Kubernetes cluster?", - link: "https://goto.prowler.com/provider-k8s", - }; - default: - return { - text: "How to setup a provider?", - link: "https://goto.prowler.com/provider-help", - }; - } - }; - return (
    diff --git a/ui/lib/external-urls.ts b/ui/lib/external-urls.ts new file mode 100644 index 0000000000..cea7a694ae --- /dev/null +++ b/ui/lib/external-urls.ts @@ -0,0 +1,45 @@ +export const getProviderHelpText = (provider: string) => { + switch (provider) { + case "aws": + return { + text: "Need help connecting your AWS account?", + link: "https://goto.prowler.com/provider-aws", + }; + case "azure": + return { + text: "Need help connecting your Azure subscription?", + link: "https://goto.prowler.com/provider-azure", + }; + case "m365": + return { + text: "Need help connecting your Microsoft 365 account?", + link: "https://goto.prowler.com/provider-m365", + }; + case "gcp": + return { + text: "Need help connecting your GCP project?", + link: "https://goto.prowler.com/provider-gcp", + }; + case "kubernetes": + return { + text: "Need help connecting your Kubernetes cluster?", + link: "https://goto.prowler.com/provider-k8s", + }; + default: + return { + text: "How to setup a provider?", + link: "https://goto.prowler.com/provider-help", + }; + } +}; + +export const getAWSCredentialsTemplateLinks = () => { + return { + cloudformation: + "https://github.com/prowler-cloud/prowler/blob/master/permissions/templates/cloudformation/prowler-scan-role.yml", + cloudformationQuickLink: + "https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateURL=https%3A%2F%2Fprowler-cloud-public.s3.eu-west-1.amazonaws.com%2Fpermissions%2Ftemplates%2Faws%2Fcloudformation%2Fprowler-scan-role.yml&stackName=ProwlerScanRole¶m_ExternalId=", + terraform: + "https://github.com/prowler-cloud/prowler/blob/master/permissions/templates/terraform/main.tf", + }; +}; diff --git a/ui/lib/index.ts b/ui/lib/index.ts index 6560f7b5a9..6e1761c9d6 100644 --- a/ui/lib/index.ts +++ b/ui/lib/index.ts @@ -1,3 +1,4 @@ +export * from "./external-urls"; export * from "./helper"; export * from "./menu-list"; export * from "./utils"; From f8c840f283eb4973d2d8798a21d17d0175812fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?= Date: Wed, 14 May 2025 10:02:41 +0200 Subject: [PATCH 311/359] fix: ensure proper folder creation (#7729) --- api/src/backend/api/tests/test_views.py | 94 ++++++++++++---------- api/src/backend/tasks/tests/test_export.py | 39 +++++---- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 91de5775c9..0608c4a378 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -2,7 +2,9 @@ import glob import io import json import os +import tempfile from datetime import datetime, timedelta, timezone +from pathlib import Path from unittest.mock import ANY, MagicMock, Mock, patch import jwt @@ -2318,35 +2320,34 @@ class TestScanViewSet: assert response.status_code == 404 assert response.json()["errors"]["detail"] == "The scan has no reports." - def test_report_local_file( - self, authenticated_client, scans_fixture, tmp_path, monkeypatch - ): - """ - When output_location is a local file path, the view should read the file from disk - and return it with proper headers. - """ + def test_report_local_file(self, authenticated_client, scans_fixture, monkeypatch): scan = scans_fixture[0] - file_content = b"local zip file content" - file_path = tmp_path / "report.zip" - file_path.write_bytes(file_content) + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + base_tmp = tmp_path / "report_local_file" + base_tmp.mkdir(parents=True, exist_ok=True) - scan.output_location = str(file_path) - scan.state = StateChoices.COMPLETED - scan.save() + file_content = b"local zip file content" + file_path = base_tmp / "report.zip" + file_path.write_bytes(file_content) - monkeypatch.setattr( - glob, - "glob", - lambda pattern: [str(file_path)] if pattern == str(file_path) else [], - ) + scan.output_location = str(file_path) + scan.state = StateChoices.COMPLETED + scan.save() - url = reverse("scan-report", kwargs={"pk": scan.id}) - response = authenticated_client.get(url) - assert response.status_code == 200 - assert response.content == file_content - content_disposition = response.get("Content-Disposition") - assert content_disposition.startswith('attachment; filename="') - assert f'filename="{file_path.name}"' in content_disposition + monkeypatch.setattr( + glob, + "glob", + lambda pattern: [str(file_path)] if pattern == str(file_path) else [], + ) + + url = reverse("scan-report", kwargs={"pk": scan.id}) + response = authenticated_client.get(url) + assert response.status_code == 200 + assert response.content == file_content + content_disposition = response.get("Content-Disposition") + assert content_disposition.startswith('attachment; filename="') + assert f'filename="{file_path.name}"' in content_disposition def test_compliance_invalid_framework(self, authenticated_client, scans_fixture): scan = scans_fixture[0] @@ -2481,31 +2482,36 @@ class TestScanViewSet: ) def test_compliance_local_file( - self, authenticated_client, scans_fixture, tmp_path, monkeypatch + self, authenticated_client, scans_fixture, monkeypatch ): scan = scans_fixture[0] scan.state = StateChoices.COMPLETED - base = tmp_path / "reports" - comp_dir = base / "compliance" - comp_dir.mkdir(parents=True) - fname = comp_dir / "scan_cis.csv" - fname.write_bytes(b"ignored") - scan.output_location = str(base / "scan.zip") - scan.save() + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + base = tmp_path / "reports" + comp_dir = base / "compliance" + comp_dir.mkdir(parents=True, exist_ok=True) + fname = comp_dir / "scan_cis.csv" + fname.write_bytes(b"ignored") - monkeypatch.setattr( - glob, - "glob", - lambda p: [str(fname)] if p.endswith("*_cis_1.4_aws.csv") else [], - ) + scan.output_location = str(base / "scan.zip") + scan.save() - url = reverse("scan-compliance", kwargs={"pk": scan.id, "name": "cis_1.4_aws"}) - resp = authenticated_client.get(url) - assert resp.status_code == status.HTTP_200_OK - cd = resp["Content-Disposition"] - assert cd.startswith('attachment; filename="') - assert cd.endswith(f'filename="{fname.name}"') + monkeypatch.setattr( + glob, + "glob", + lambda p: [str(fname)] if p.endswith("*_cis_1.4_aws.csv") else [], + ) + + url = reverse( + "scan-compliance", kwargs={"pk": scan.id, "name": "cis_1.4_aws"} + ) + resp = authenticated_client.get(url) + assert resp.status_code == status.HTTP_200_OK + cd = resp["Content-Disposition"] + assert cd.startswith('attachment; filename="') + assert cd.endswith(f'filename="{fname.name}"') @patch("api.v1.views.Task.objects.get") @patch("api.v1.views.TaskSerializer") diff --git a/api/src/backend/tasks/tests/test_export.py b/api/src/backend/tasks/tests/test_export.py index 2aefbce9f9..6811fe7449 100644 --- a/api/src/backend/tasks/tests/test_export.py +++ b/api/src/backend/tasks/tests/test_export.py @@ -1,5 +1,6 @@ import os import zipfile +from pathlib import Path from unittest.mock import MagicMock, patch import pytest @@ -14,8 +15,9 @@ from tasks.jobs.export import ( @pytest.mark.django_db class TestOutputs: - def test_compress_output_files_creates_zip(self, tmp_path): - output_dir = tmp_path / "output" + def test_compress_output_files_creates_zip(self, tmpdir): + base_tmp = Path(str(tmpdir.mkdir("compress_output"))) + output_dir = base_tmp / "output" output_dir.mkdir() file_path = output_dir / "result.csv" file_path.write_text("data") @@ -54,16 +56,16 @@ class TestOutputs: @patch("tasks.jobs.export.get_s3_client") @patch("tasks.jobs.export.base") - def test_upload_to_s3_success(self, mock_base, mock_get_client, tmp_path): + def test_upload_to_s3_success(self, mock_base, mock_get_client, tmpdir): mock_base.DJANGO_OUTPUT_S3_AWS_OUTPUT_BUCKET = "test-bucket" - zip_path = tmp_path / "outputs.zip" + base_tmp = Path(str(tmpdir.mkdir("upload_success"))) + zip_path = base_tmp / "outputs.zip" zip_path.write_bytes(b"dummy") - compliance_dir = tmp_path / "compliance" + compliance_dir = base_tmp / "compliance" compliance_dir.mkdir() - compliance_file = compliance_dir / "report.csv" - compliance_file.write_text("ok") + (compliance_dir / "report.csv").write_text("ok") client_mock = MagicMock() mock_get_client.return_value = client_mock @@ -72,7 +74,6 @@ class TestOutputs: expected_uri = "s3://test-bucket/tenant-id/scan-id/outputs.zip" assert result == expected_uri - assert client_mock.upload_file.call_count == 2 @patch("tasks.jobs.export.get_s3_client") @@ -84,12 +85,14 @@ class TestOutputs: @patch("tasks.jobs.export.get_s3_client") @patch("tasks.jobs.export.base") - def test_upload_to_s3_skips_non_files(self, mock_base, mock_get_client, tmp_path): + def test_upload_to_s3_skips_non_files(self, mock_base, mock_get_client, tmpdir): mock_base.DJANGO_OUTPUT_S3_AWS_OUTPUT_BUCKET = "test-bucket" - zip_path = tmp_path / "results.zip" + base_tmp = Path(str(tmpdir.mkdir("upload_skips_non_files"))) + + zip_path = base_tmp / "results.zip" zip_path.write_bytes(b"zip") - compliance_dir = tmp_path / "compliance" + compliance_dir = base_tmp / "compliance" compliance_dir.mkdir() (compliance_dir / "subdir").mkdir() @@ -100,7 +103,6 @@ class TestOutputs: expected_uri = "s3://test-bucket/tenant/scan/results.zip" assert result == expected_uri - client_mock.upload_file.assert_called_once() @patch( @@ -110,23 +112,26 @@ class TestOutputs: @patch("tasks.jobs.export.base") @patch("tasks.jobs.export.logger.error") def test_upload_to_s3_failure_logs_error( - self, mock_logger, mock_base, mock_get_client, tmp_path + self, mock_logger, mock_base, mock_get_client, tmpdir ): mock_base.DJANGO_OUTPUT_S3_AWS_OUTPUT_BUCKET = "bucket" - zip_path = tmp_path / "zipfile.zip" + + base_tmp = Path(str(tmpdir.mkdir("upload_failure_logs"))) + zip_path = base_tmp / "zipfile.zip" zip_path.write_bytes(b"zip") - compliance_dir = tmp_path / "compliance" + compliance_dir = base_tmp / "compliance" compliance_dir.mkdir() (compliance_dir / "report.csv").write_text("csv") _upload_to_s3("tenant", str(zip_path), "scan") mock_logger.assert_called() - def test_generate_output_directory_creates_paths(self, tmp_path): + def test_generate_output_directory_creates_paths(self, tmpdir): from prowler.config.config import output_file_timestamp - base_dir = str(tmp_path) + base_tmp = Path(str(tmpdir.mkdir("generate_output"))) + base_dir = str(base_tmp) tenant_id = "t1" scan_id = "s1" provider = "aws" From 9ecf5707908f797f992b3d0094a79ff60e1734f0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 10:06:52 +0200 Subject: [PATCH 312/359] feat(github): add new check `repository_code_changes_multi_approval_requirement` (#6160) Co-authored-by: MrCloudSec --- README.md | 2 +- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...s_multi_approval_requirement.metadata.json | 30 ++++ ...code_changes_multi_approval_requirement.py | 38 +++++ ...y_public_has_securitymd_file.metadata.json | 2 +- .../repository_public_has_securitymd_file.py | 2 +- .../services/repository/repository_service.py | 48 +++++- ...changes_multi_approval_requirement_test.py | 151 ++++++++++++++++++ ...ository_public_has_securitymd_file_test.py | 6 + .../repository/repository_service_test.py | 9 +- 11 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py create mode 100644 tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py diff --git a/README.md b/README.md index 5e20971be0..221a29d35e 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ prowler dashboard | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | -| GitHub | 1 | 1 | 1 | 0 | +| GitHub | 2 | 1 | 1 | 0 | | M365 | 44 | 2 | 2 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index d147982f4d..7b1498e2dc 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) +- Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/__init__.py b/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json b/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json new file mode 100644 index 0000000000..8390543480 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_code_changes_multi_approval_requirement", + "CheckTitle": "Check if repositories require at least 2 code changes approvals", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "github:user-id:repository/repository-name", + "Severity": "high", + "ResourceType": "GitHubRepository", + "Description": "Ensure that repositories require at least 2 code changes approvals before merging a pull request.", + "Risk": "If repositories do not require at least 2 code changes approvals before merging a pull request, it is possible that code changes are not being reviewed by multiple people, which could lead to the introduction of bugs or security vulnerabilities.", + "RelatedUrl": "https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/approving-a-pull-request-with-required-reviews", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "To require at least 2 code changes approvals before merging a pull request, navigate to the repository settings, click on 'Branches', and then 'Add rule'.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-pull-request-reviews-before-merging" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py b/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py new file mode 100644 index 0000000000..599b77a6f5 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py @@ -0,0 +1,38 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_code_changes_multi_approval_requirement(Check): + """Check if a repository enforces at least 2 approvals for code changes + + This class verifies whether each repository enforces at least 2 approvals for code changes. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository code changes enforce multi approval requirement check + + Iterates over each repository and checks if the repository enforces at least 2 approvals for code changes. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.approval_count is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = f"Repository {repo.name} does not enforce at least 2 approvals for code changes." + + if repo.approval_count >= 2: + report.status = "PASS" + report.status_extended = f"Repository {repo.name} does enforce at least 2 approvals for code changes." + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json index 69c9446aa7..4b2cdf24f8 100644 --- a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json +++ b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.metadata.json @@ -7,7 +7,7 @@ "SubServiceName": "", "ResourceIdTemplate": "github:user-id:repository/repository-name", "Severity": "low", - "ResourceType": "Other", + "ResourceType": "GitHubRepository", "Description": "Ensure that public repositories have a SECURITY.md file", "Risk": "Not having a SECURITY.md file in a public repository may lead to security vulnerabilities being overlooked by users and contributors.", "RelatedUrl": "https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository", diff --git a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py index 342b8f5e9f..c1ec7b51e4 100644 --- a/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py +++ b/prowler/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file.py @@ -22,7 +22,7 @@ class repository_public_has_securitymd_file(Check): """ findings = [] for repo in repository_client.repositories.values(): - if not repo.private: + if not repo.private and repo.securitymd is not None: report = CheckReportGithub( metadata=self.metadata(), resource=repo, repository=repo.name ) diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index f7c2c02760..d2ab5d3658 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -17,17 +17,56 @@ class Repository(GithubService): try: for client in self.clients: for repo in client.get_user().get_repos(): + default_branch = repo.default_branch + securitymd_exists = False try: securitymd_exists = repo.get_contents("SECURITY.md") is not None - except Exception: - securitymd_exists = False + except Exception as error: + if "404" in str(error): + securitymd_exists = False + else: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + securitymd_exists = None + + require_pr = False + approval_cnt = 0 + try: + branch = repo.get_branch(default_branch) + if branch.protected: + protection = branch.get_protection() + if protection: + require_pr = ( + protection.required_pull_request_reviews is not None + ) + approval_cnt = ( + protection.required_pull_request_reviews.required_approving_review_count + if require_pr + else 0 + ) + except Exception as error: + if "404" in str(error): + require_pr = False + approval_cnt = 0 + else: + require_pr = None + approval_cnt = None + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + repos[repo.id] = Repo( id=repo.id, name=repo.name, full_name=repo.full_name, + default_branch=repo.default_branch, private=repo.private, securitymd=securitymd_exists, + require_pull_request=require_pr, + approval_count=approval_cnt, ) + except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -41,5 +80,8 @@ class Repo(BaseModel): id: int name: str full_name: str + default_branch: str private: bool - securitymd: Optional[bool] = False + securitymd: Optional[bool] + require_pull_request: Optional[bool] + approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py b/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py new file mode 100644 index 0000000000..ba0b28e673 --- /dev/null +++ b/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py @@ -0,0 +1,151 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_code_changes_multi_approval_requirement: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( + repository_code_changes_multi_approval_requirement, + ) + + check = repository_code_changes_multi_approval_requirement() + result = check.execute() + assert len(result) == 0 + + def test_repository_no_require_pull_request(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch="main", + private=False, + securitymd=False, + require_pull_request=False, + approval_count=0, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( + repository_code_changes_multi_approval_requirement, + ) + + check = repository_code_changes_multi_approval_requirement() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not enforce at least 2 approvals for code changes." + ) + + def test_repository_no_approvals(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch="master", + private=False, + securitymd=False, + require_pull_request=True, + approval_count=0, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( + repository_code_changes_multi_approval_requirement, + ) + + check = repository_code_changes_multi_approval_requirement() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not enforce at least 2 approvals for code changes." + ) + + def test_repository_two_approvals(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch="master", + private=False, + securitymd=True, + require_pull_request=True, + approval_count=2, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( + repository_code_changes_multi_approval_requirement, + ) + + check = repository_code_changes_multi_approval_requirement() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does enforce at least 2 approvals for code changes." + ) diff --git a/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py b/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py index ccbf02c075..776d557252 100644 --- a/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py +++ b/tests/providers/github/services/repository/repository_public_has_securitymd_file/repository_public_has_securitymd_file_test.py @@ -35,8 +35,11 @@ class Test_repository_public_has_securitymd_file_test: id=1, name=repo_name, full_name="account-name/repo1", + default_branch="main", private=False, securitymd=False, + require_pull_request=False, + approval_count=0, ), } @@ -73,8 +76,11 @@ class Test_repository_public_has_securitymd_file_test: id=1, name=repo_name, full_name="account-name/repo1", + default_branch="main", private=False, securitymd=True, + require_pull_request=False, + approval_count=0, ), } diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index a375b5c62c..bc1f709ead 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -13,8 +13,11 @@ def mock_list_repositories(_): id=1, name="repo1", full_name="account-name/repo1", + default_branch="main", private=False, - securitymd=False, + securitymd=True, + require_pull_request=True, + approval_count=2, ), } @@ -38,4 +41,6 @@ class Test_Repository_Service: assert repository_service.repositories[1].name == "repo1" assert repository_service.repositories[1].full_name == "account-name/repo1" assert repository_service.repositories[1].private is False - assert repository_service.repositories[1].securitymd is False + assert repository_service.repositories[1].securitymd + assert repository_service.repositories[1].require_pull_request + assert repository_service.repositories[1].approval_count == 2 From 484a773f5ba264308b72f70af2faac91eadc7d09 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 10:40:26 +0200 Subject: [PATCH 313/359] feat(github): add new service `Organization` (#6300) Co-authored-by: MrCloudSec --- prowler/lib/check/models.py | 2 +- .../github/services/organization/__init__.py | 0 .../organization/organization_client.py | 6 ++++ .../organization/organization_service.py | 33 +++++++++++++++++ .../organization/organization_service_test.py | 35 +++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/github/services/organization/__init__.py create mode 100644 prowler/providers/github/services/organization/organization_client.py create mode 100644 prowler/providers/github/services/organization/organization_service.py create mode 100644 tests/providers/github/services/organization/organization_service_test.py diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index 5e240f74cc..0ef3195b2a 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -556,7 +556,7 @@ class CheckReportGithub(Check_Report): resource: Any, resource_name: str = None, resource_id: str = None, - repository: str = None, + repository: str = "global", ) -> None: """Initialize the GitHub Check's finding information. diff --git a/prowler/providers/github/services/organization/__init__.py b/prowler/providers/github/services/organization/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/organization/organization_client.py b/prowler/providers/github/services/organization/organization_client.py new file mode 100644 index 0000000000..8c05c87178 --- /dev/null +++ b/prowler/providers/github/services/organization/organization_client.py @@ -0,0 +1,6 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.github.services.organization.organization_service import ( + Organization, +) + +organization_client = Organization(Provider.get_global_provider()) diff --git a/prowler/providers/github/services/organization/organization_service.py b/prowler/providers/github/services/organization/organization_service.py new file mode 100644 index 0000000000..64c2e7c0d8 --- /dev/null +++ b/prowler/providers/github/services/organization/organization_service.py @@ -0,0 +1,33 @@ +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.github.lib.service.service import GithubService + + +class Organization(GithubService): + def __init__(self, provider): + super().__init__(__class__.__name__, provider) + self.organizations = self._list_organizations() + + def _list_organizations(self): + logger.info("Organization - Listing Organizations...") + organizations = {} + try: + for client in self.clients: + for org in client.get_user().get_orgs(): + organizations[org.id] = Org( + id=org.id, + name=org.login, + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return organizations + + +class Org(BaseModel): + """Model for Github Organization""" + + id: int + name: str diff --git a/tests/providers/github/services/organization/organization_service_test.py b/tests/providers/github/services/organization/organization_service_test.py new file mode 100644 index 0000000000..02dabf80ff --- /dev/null +++ b/tests/providers/github/services/organization/organization_service_test.py @@ -0,0 +1,35 @@ +from unittest.mock import patch + +from prowler.providers.github.services.organization.organization_service import ( + Org, + Organization, +) +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +def mock_list_organizations(_): + return { + 1: Org( + id=1, + name="test-organization", + ), + } + + +@patch( + "prowler.providers.github.services.organization.organization_service.Organization._list_organizations", + new=mock_list_organizations, +) +class Test_Repository_Service: + def test_get_client(self): + repository_service = Organization(set_mocked_github_provider()) + assert repository_service.clients[0].__class__.__name__ == "Github" + + def test_get_service(self): + repository_service = Organization(set_mocked_github_provider()) + assert repository_service.__class__.__name__ == "Organization" + + def test_list_organizations(self): + repository_service = Organization(set_mocked_github_provider()) + assert len(repository_service.organizations) == 1 + assert repository_service.organizations[1].name == "test-organization" From a765c1543eda8dc11a4a55556dc58640ecce2da1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 10:47:33 +0200 Subject: [PATCH 314/359] feat: add GitHub provider documentation and CIS v1.0.0 compliance (#6116) Co-authored-by: MrCloudSec Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- docs/getting-started/requirements.md | 16 + docs/index.md | 25 + docs/tutorials/github/authentication.md | 44 + prowler/CHANGELOG.md | 1 + prowler/__main__.py | 31 + prowler/compliance/github/cis_1.0_github.json | 2590 ++++++++++++++++- prowler/lib/cli/parser.py | 1 + .../lib/outputs/compliance/cis/cis_github.py | 101 + prowler/lib/outputs/compliance/cis/models.py | 31 + .../lib/outputs/compliance/compliance_test.py | 52 + ...mpliance_json_from_csv_for_cis10_github.py | 40 + 11 files changed, 2929 insertions(+), 3 deletions(-) create mode 100644 docs/tutorials/github/authentication.md create mode 100644 prowler/lib/outputs/compliance/cis/cis_github.py create mode 100644 util/generate_compliance_json_from_csv_for_cis10_github.py diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index d2ebd8a12b..a9318228ab 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -466,3 +466,19 @@ The required modules are: - [ExchangeOnlineManagement](https://www.powershellgallery.com/packages/ExchangeOnlineManagement/3.6.0): Minimum version 3.6.0. Required for several checks across Exchange, Defender, and Purview. - [MicrosoftTeams](https://www.powershellgallery.com/packages/MicrosoftTeams/6.6.0): Minimum version 6.6.0. Required for all Teams checks. + +## GitHub +### Authentication + +Prowler supports multiple methods to [authenticate with GitHub](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api). These include: + +- **Personal Access Token (PAT)** +- **OAuth App Token** +- **GitHub App Credentials** + +This flexibility allows you to scan and analyze your GitHub account, including repositories, organizations, and applications, using the method that best suits your use case. + +The provided credentials must have the appropriate permissions to perform all the required checks. + +???+ note + GitHub App Credentials support less checks than other authentication methods. diff --git a/docs/index.md b/docs/index.md index a92d4b0444..ff0f3237a2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -565,6 +565,7 @@ kubectl logs prowler-XXXXX --namespace prowler-ns ???+ note By default, `prowler` will scan all namespaces in your active Kubernetes context. Use the flag `--context` to specify the context to be scanned and `--namespaces` to specify the namespaces to be scanned. + #### Microsoft 365 With M365 you need to specify which auth method is going to be used: @@ -587,5 +588,29 @@ prowler m365 --browser-auth --tenant-id "XXXXXXXX" See more details about M365 Authentication in [Requirements](getting-started/requirements.md#microsoft-365) +#### GitHub + +Prowler allows you to scan your GitHub account, including your repositories, organizations or applications. + +There are several supported login methods: + +```console +# Personal Access Token (PAT): +prowler github --personal-access-token pat + +# OAuth App Token: +prowler github --oauth-app-token oauth_token + +# GitHub App Credentials: +prowler github --github-app-id app_id --github-app-key app_key +``` + +???+ note + If no login method is explicitly provided, Prowler will automatically attempt to authenticate using environment variables in the following order of precedence: + + 1. `GITHUB_PERSONAL_ACCESS_TOKEN` + 2. `OAUTH_APP_TOKEN` + 3. `GITHUB_APP_ID` and `GITHUB_APP_KEY` + ## Prowler v2 Documentation For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md). diff --git a/docs/tutorials/github/authentication.md b/docs/tutorials/github/authentication.md new file mode 100644 index 0000000000..29f7795aba --- /dev/null +++ b/docs/tutorials/github/authentication.md @@ -0,0 +1,44 @@ +# GitHub Authentication + +Prowler supports multiple methods to [authenticate with GitHub](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api). These include: + +- **Personal Access Token (PAT)** +- **OAuth App Token** +- **GitHub App Credentials** + +This flexibility allows you to scan and analyze your GitHub account, including repositories, organizations, and applications, using the method that best suits your use case. + +## Supported Login Methods + +Here are the available login methods and their respective flags: + +### Personal Access Token (PAT) +Use this method by providing your personal access token directly. + +```console +prowler github --personal-access-token pat +``` + +### OAuth App Token +Authenticate using an OAuth app token. + +```console +prowler github --oauth-app-token oauth_token +``` + +### GitHub App Credentials +Use GitHub App credentials by specifying the App ID and the private key. + +```console +prowler github --github-app-id app_id --github-app-key app_key +``` + +### Automatic Login Method Detection +If no login method is explicitly provided, Prowler will automatically attempt to authenticate using environment variables in the following order of precedence: + +1. `GITHUB_PERSONAL_ACCESS_TOKEN` +2. `OAUTH_APP_TOKEN` +3. `GITHUB_APP_ID` and `GITHUB_APP_KEY` + +???+ note + Ensure the corresponding environment variables are set up before running Prowler for automatic detection if you don't plan to specify the login method. diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 7b1498e2dc..fdd357b1c2 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) +- Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) diff --git a/prowler/__main__.py b/prowler/__main__.py index 95b08d6a15..6aa74c98ab 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -50,6 +50,7 @@ from prowler.lib.outputs.compliance.aws_well_architected.aws_well_architected im 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_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.compliance import display_compliance_table @@ -787,6 +788,36 @@ def prowler(): generated_outputs["compliance"].append(generic_compliance) generic_compliance.batch_write_data_to_file() + elif provider == "github": + for compliance_name in input_compliance_frameworks: + if compliance_name.startswith("cis_"): + # Generate CIS Finding Object + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + cis = GithubCIS( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + create_file_descriptor=True, + file_path=filename, + ) + generated_outputs["compliance"].append(cis) + cis.batch_write_data_to_file() + else: + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + generic_compliance = GenericCompliance( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + create_file_descriptor=True, + file_path=filename, + ) + generated_outputs["compliance"].append(generic_compliance) + generic_compliance.batch_write_data_to_file() + # AWS Security Hub Integration if provider == "aws": # Send output to S3 if needed (-B / -D) for all the output formats diff --git a/prowler/compliance/github/cis_1.0_github.json b/prowler/compliance/github/cis_1.0_github.json index f5431f2d44..3f0037c9e0 100644 --- a/prowler/compliance/github/cis_1.0_github.json +++ b/prowler/compliance/github/cis_1.0_github.json @@ -1,7 +1,2591 @@ { "Framework": "CIS", "Version": "1.0", - "Provider": "Github", - "Description": "This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for securing the Software Supply Chain.", - "Requirements": [] + "Provider": "GitHub", + "Description": "This document provides prescriptive guidance for establishing a secure configuration posture for securing GitHub.", + "Requirements": [ + { + "Id": "Id", + "Description": "Title", + "Checks": [ + "Checks" + ], + "Attributes": [ + { + "Section": "Attributes_Section", + "Profile": "Attributes_Level", + "AssessmentStatus": "Attributes_AssessmentStatus", + "Description": "Attributes_Description", + "RationaleStatement": "Attributes_RationaleStatement", + "ImpactStatement": "Attributes_ImpactStatement", + "RemediationProcedure": "Attributes_RemediationProcedure", + "AuditProcedure": "Attributes_AuditProcedure", + "AdditionalInformation": "Attributes_AdditionalInformation", + "References": "Attributes_References" + } + ] + }, + { + "Id": "1.1.1", + "Description": "Ensure any changes to code are tracked in a version control platform", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Manage all code projects in a version control platform.", + "RationaleStatement": "Version control platforms keep track of every modification to code. They represent the cornerstone of code security, as well as allowing for better code collaboration within engineering teams. With granular access management, change tracking, and key signing of code edits, version control platforms are the first step in securing the software supply chain.", + "ImpactStatement": "", + "RemediationProcedure": "Upload existing code projects to a dedicated Github organization and repositories and create an identity for each active team member who might contribute or need access to it.", + "AuditProcedure": "Ensure that all code activity is managed through Github repository for every micro-service or application developed by an organization.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.2", + "Description": "Ensure any change to code can be traced back to its associated task", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use a task management system to trace any code back to its associated task.", + "RationaleStatement": "The ability to trace each piece of code back to its associated task simplifies the Agile and DevOps process by enabling transparency of any code changes. This allows faster remediation of bugs and security issues, while also making it harder to push unauthorized code changes to sensitive projects. Additionally, using a task management system simplifies achieving compliance, as it is easier to track each regulation.", + "ImpactStatement": "", + "RemediationProcedure": "Use a task management system to manage tasks as the starting point for each code change. Whether it is a new feature, bug fix, or security fix - all should originate from a dedicated task (ticket) in your organization's task management system. These tasks should also be linked to the code changes themselves in a way that is easy to follow: from code to task, and from task back to code.", + "AuditProcedure": "Ensure every code change can be traced back to its origin task in a task management system.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.3", + "Description": "Ensure any change to code receives approval of two strongly authenticated users", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Ensure that every code change is reviewed and approved by two authorized contributors who are both strongly authenticated - using Multi-Factor Authentication (MFA), from the team relevant to the code change.", + "RationaleStatement": "To prevent malicious or unauthorized code changes, the first layer of protection is the process of code review. This process involves engineer teammates reviewing each other's code for errors, optimizations, and general knowledge-sharing. With proper peer reviews in place, an organization can detect unwanted code changes very early in the process of release. In order to help facilitate code review, companies should employ automation to verify that every code change has been reviewed and approved by at least two team members before it is pushed into the code base. These team members should be from the team that is related to the code change, so it will be a meaningful review.", + "ImpactStatement": "To enforce a code review requirement, verification for a minimum of two reviewers must be put into place. This will ensure new code will not be able to be pushed to the code base before it has received two independent approvals.", + "RemediationProcedure": "For every code repository in use, perform the next steps to require two approvals from the specific code repository team in order to push new code to the code base:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you added the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Check **Require a pull request before merging** and **Require approvals**, and set **Required number of approvals before merging** to 2.\n 5. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, perform the next steps to verify that two approvals from the specific code repository team are required to push new code to the code base:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require a pull request before merging** and **Require approvals** are checked, and verify that **Required number of approvals before merging** is set to 2.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.4", + "Description": "Ensure previous approvals are dismissed when updates are introduced to a code change proposal", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure that when a proposed code change is updated, previous approvals are declined, and new approvals are required.", + "RationaleStatement": "An approval process is necessary when code changes are suggested. Through this approval process, however, changes can still be made to the original proposal even after some approvals have already been given. This means malicious code can find its way into the code base even if the organization has enforced a review policy. To ensure this is not possible, outdated approvals must be declined when changes to the suggestion are introduced.", + "ImpactStatement": "If new code changes are pushed to a specific proposal, all previously accepted code change proposals must be declined.", + "RemediationProcedure": "For each code repository in use, perform the next steps to enforce dismissal of given approvals to code change suggestions if those suggestions were updated:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you added the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require pull request reviews before merging** and then **Dismiss stale pull request approvals when new commits are pushed**.\n 5. Click **Create** or **Save changes**.", + "AuditProcedure": "For each code repository in use, perform the next steps to verify that each updated code suggestion declines the previously received approvals:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require a pull request before merging** is checked, and verify that **Dismiss stale pull request approvals when new commits are pushed** is checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.5", + "Description": "Ensure there are restrictions on who can dismiss code change reviews", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Only trusted users should be allowed to dismiss code change reviews.", + "RationaleStatement": "Dismissing a code change review permits users to merge new suggested code changes without going through the standard process of approvals. Controlling who can perform this action will prevent malicious actors from simply dismissing the required reviews to code changes and merging malicious or dysfunctional code into the code base.", + "ImpactStatement": "In cases where a code change proposal has been updated since it was last reviewed and the person who reviewed it isn't available for approval, a general collaborator would not be able to merge their code changes until a user with \"dismiss review\" abilities could dismiss the open review.\n \n\n Users who are not allowed to dismiss code change reviews will not be permitted to do so, and thus are unable to waive the standard flow of approvals.", + "RemediationProcedure": "For each code repository in use, perform the next steps to restrict dismissal of code changes reviews unless it is necessary:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you added the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 4. Select **Require pull request reviews before merging** and **Restrict who can dismiss pull request reviews**.\n 5. Do not add any user or team unless it is obligatory. If it is obligatory, carefully select the users or teams whom you trust with the ability to dismiss code change reviews.\n 6. Click **Create** or **Save changes**.", + "AuditProcedure": "For each code repository in use, perform the next steps to verify that only trusted users are allowed to dismiss code change reviews: \n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 4. Verify that **Require a pull request before merging** and **Restrict who can dismiss pull request reviews** is checked.\n 5. Verify that no users and teams are specified except for organization and repository admins. If it is obligatory, verify that the users or teams specified were carefully selected to be trusted with the ability to dismiss code change reviews.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.6", + "Description": "Ensure code owners are set for extra sensitive code or configuration", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Code owners are trusted users that are responsible for reviewing and managing an important piece of code or configuration. An organization is advised to set code owners for every extremely sensitive code or configuration.", + "RationaleStatement": "Configuring code owners protects data by verifying that trusted users will notice and review every edit, thus preventing unwanted or malicious changes from potentially compromising sensitive code or configurations.", + "ImpactStatement": "Code owner users will receive notifications for every change that occurs to the code and subsequently added as reviewers of pull requests automatically.", + "RemediationProcedure": "In every code repository create a CODEOWNERS file in the root, docs/, or .github/ directory of the repository.\n In the file, specify codeowners for the .github/workflows/ directory atleast. Specify organization members you trust. For example:\n ```\n .github/workflows/ @user1 @user2\n ```", + "AuditProcedure": "In every code repository, verify that a file named CODEOWNERS exists in the root, docs/, or .github/ directory of the repository.\n In the CODEOWNERS file, verify that the users specified are users you trust.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners" + } + ] + }, + { + "Id": "1.1.7", + "Description": "Ensure code owner's review is required when a change affects owned code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure trusted code owners are required to review and approve any code change proposal made to their respective owned areas in the code base.", + "RationaleStatement": "Configuring code owners ensures that no code, especially code which could prove malicious, will slip into the source code or configuration files of a repository. This allows an organization to mark areas in the code base that are especially sensitive or more prone to an attack. It can also enforce review by specific individuals who are designated as owners to those areas so that they may filter out unauthorized or unwanted changes beforehand.", + "ImpactStatement": "If an organization enforces code owner-based reviews, some code change proposals would not be able to be merged to the codebase before specific, trusted individuals approve them.", + "RemediationProcedure": "For every code repository in use, perform the following steps to require code owners' approvals for each change proposal related to code they own:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require pull request reviews before merging** and **Require review from Code Owners**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, perform the following steps to verify that code owners are required to review all code change proposals relevant to areas they own before code merge:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 4. Ensure that **Require a pull request before merging** and **Require review from Code Owners** are checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.8", + "Description": "Ensure inactive branches are periodically reviewed and removed", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Keep track of code branches that are inactive for a lengthy period of time and periodically remove them.", + "RationaleStatement": "Git branches that have been inactive (i.e., no new changes introduced) for a long period of time are enlarging the surface of attack for malicious code injection, sensitive data leaks, and CI pipeline exploitation. They potentially contain outdated dependencies which may leave them highly vulnerable. They are more likely to be improperly managed, and could possibly be accessed by a large number of members of the organization.", + "ImpactStatement": "Removing inactive Git branches means that any code changes they contain would be removed along with them, thus work done in the past might not be accessible after auditing for inactivity.", + "RemediationProcedure": "For each code repository in use, review existing Git branches and remove those which have not been active for a period of time by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Above the list of files, click **Branches**.\n 3. Use the navigation at the top of the page to view the Stale branches. The Stale view shows all branches that no one has committed to in the last three months, ordered by the branches with the oldest commits first.\n 4. For each branch listed, either delete it by clicking the trash bin icon, or find the valid reason it still exists.\n \n\n You can perform the next steps to prevent pull request branches from becoming stale branches:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click Settings.\n 3. Under \"Pull Requests\", select **Automatically delete head branches**.", + "AuditProcedure": "For each code repository in use, verify that all existing Git branches are active or have yet to be checked for inactivity by performing the next steps:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Above the list of files, click **Branches**.\n 3. Use the navigation at the top of the page to view the Stale branches. The Stale view shows all branches that no one has committed to in the last three months, ordered by the branches with the oldest commits first.\n 4. If the list is empty, you are compliant. If the list is not empty, but there is a valid reason the branches listed are not deleted, you are compliant.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.9", + "Description": "Ensure all checks have passed before merging new code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Before a code change request can be merged to the code base, all predefined checks must successfully pass.", + "RationaleStatement": "On top of manual reviews of code changes, a code protect should contain a set of prescriptive checks which validate each change. Organizations should enforce those status checks so that changes can only be introduced if all checks have successfully passed. This set of checks should serve as the absolute quality, stability, and security conditions which must be met in order to merge new code to a project.", + "ImpactStatement": "Code changes in which all checks do not pass successfully would not be able to be pushed into the code base of the specific code repository.", + "RemediationProcedure": "For each code repository in use, require all status checks to pass before permitting a merge of new code by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", check if there is a rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require status checks to pass before merging**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For each code repository in use, verify that status checks are required to pass before allowing any code change proposal merge by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require status checks to pass before merging** is checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.10", + "Description": "Ensure open Git branches are up to date before they can be merged into code base", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Organizations should make sure each suggested code change is in full sync with the existing state of its origin code repository before allowing merging.", + "RationaleStatement": "Git branches can easily become outdated since the origin code repository is constantly being edited. This means engineers working on separate code branches can accidentally include outdated code with potential security issues which might have already been fixed, overriding the potential solutions for those security issues when merging their own changes.", + "ImpactStatement": "If enforced, outdated branches would not be able to be merged into their origin repository without first being updated to contain any recent changes.", + "RemediationProcedure": "For each code repository in use, enforce a policy to only allow merging open branches if they are current with the latest change from their original repository by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require status checks to pass before merging** and **Require branches to be up to date before merging**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For each code repository in use, verify that open branches must be updated before merging is permitted by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require status checks to pass before merging** and **Require branches to be up to date before merging** are checked.", + "AdditionalInformation": "", + "References": "https://github.blog/changelog/2022-02-03-more-ways-to-keep-your-pull-request-branch-up-to-date/" + } + ] + }, + { + "Id": "1.1.11", + "Description": "Ensure all open comments are resolved before allowing code change merging", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Organizations should enforce a \"no open comments\" policy before allowing code change merging.", + "RationaleStatement": "In an open code change proposal, reviewers can leave comments containing their questions and suggestions. These comments can also include potential bugs and security issues. Requiring all comments on a code change proposal to be resolved before it can be merged ensures that every concern is properly addressed or acknowledged before the new code changes are introduced to the code base.", + "ImpactStatement": "Code change proposals containing open comments would not be able to be merged into the code base.", + "RemediationProcedure": "For each code repository in use, require open comments to be resolved before the relevant code change can be merged by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require conversation resolution before merging**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, verify that each merged code change does not contain open, unattended comments by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require conversation resolution before merging** is checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.12", + "Description": "Ensure verification of signed commits for new changes before merging", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Ensure every commit in a pull request is signed and verified before merging.", + "RationaleStatement": "Signing commits, or requiring to sign commits, gives other users confidence about the origin of a specific code change. It ensures that the author of the change is not hidden and is verified by the version control system, thus the change comes from a trusted source.", + "ImpactStatement": "Pull requests with unsigned commits cannot be merged.", + "RemediationProcedure": "For each repository in use, enforce the branch protection rule of requiring signed commits, and make sure only signed commits are capable of merging by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require signed commits**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "Ensure only signed commits can be merged for every branch, especially the main branch, via branch protection rules by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require signed commits** is checked.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits" + } + ] + }, + { + "Id": "1.1.13", + "Description": "Ensure linear history is required", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Linear history is the name for Git history where all commits are listed in chronological order, one after another. Such history exists if a pull request is merged either by rebase merge (re-order the commits history) or squash merge (squashes all commits to one). Ensure that linear history is required by requiring the use of rebase or squash merge when merging a pull request.", + "RationaleStatement": "Enforcing linear history produces a clear record of activity, and as such it offers specific advantages: it is easier to follow, easier to revert a change, and bugs can be found more easily.", + "ImpactStatement": "Pull request cannot be merged except squash or rebase merge.", + "RemediationProcedure": "For every code repository in use, perform the following steps to require linear history and/or allow only rebase merge and squash merge:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Require linear history**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, perform the following steps to verify that linear history is required and/or that only squash merge and rebase merge are allowed:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Require linear history** is checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.14", + "Description": "Ensure branch protection rules are enforced for administrators", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure administrators are subject to branch protection rules.", + "RationaleStatement": "Administrators by default are excluded from any branch protection rules. This means these privileged users (both on the repository and organization levels) are not subject to protections meant to prevent untrusted code insertion, including malicious code. This is extremely important since administrator accounts are often targeted for account hijacking due to their privileged role.", + "ImpactStatement": "Administrator users won't be able to push code directly to the protected branch without being compliant with listed branch protection rules.", + "RemediationProcedure": "For every code repository in use, enforce branch protection rules on administrators as well, by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Do not allow bypassing the above settings**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, validate branch protection rules also apply to administrator accounts by performing the next steps:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Do not allow bypassing the above settings** is checked.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule" + } + ] + }, + { + "Id": "1.1.15", + "Description": "Ensure pushing or merging of new code is restricted to specific individuals or teams", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Ensure that only trusted users can push or merge new code to protected branches.", + "RationaleStatement": "Requiring that only trusted users may push or merge new changes reduces the risk of unverified code, especially malicious code, to a protected branch by reducing the number of trusted users who are capable of doing such.", + "ImpactStatement": "Only administrators and trusted users can push or merge to the protected branch.", + "RemediationProcedure": "For every code repository in use, allow only trusted and responsible users to push or merge new code by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4.Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Select **Restrict who can push to matching branches** and choose trusted and responsible users and teams who will have the permission to do so. \n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, ensure only trusted and responsible users can push or merge new code by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Restrict who can push to matching branches** is checked and that only trusted and responsible users and teams are selected.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule" + } + ] + }, + { + "Id": "1.1.16", + "Description": "Ensure force push code to branches is denied", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "The \"Force Push\" option allows users with \"Push\" permissions to force their changes directly to the branch without a pull request, and thus should be disabled.", + "RationaleStatement": "The \"Force Push\" option allows users to override the existing code with their own code. This can lead to both intentional and unintentional data loss, as well as data infection with malicious code. Disabling the \"Force Push\" option prohibits users from forcing their changes to the master branch, which ultimately prevents malicious code from entering source code.", + "ImpactStatement": "Users cannot force push to protected branches.", + "RemediationProcedure": "For each repository in use, block the option to \"Force Push\" code by performing the following: \n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Uncheck **Allow force pushes**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For every code repository in use, validate that no one can force push code by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Allow force pushes** is not checked.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule" + } + ] + }, + { + "Id": "1.1.17", + "Description": "Ensure branch deletions are denied", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure that users with only push access are incapable of deleting a protected branch.", + "RationaleStatement": "When enabling deletion of a protected branch, any user with at least push access to the repository can delete a branch. This can be potentially dangerous, as a simple human mistake or a hacked account can lead to data loss if a branch is deleted. It is therefore crucial to prevent such incidents by denying protected branch deletion.", + "ImpactStatement": "Protected branches cannot be deleted.", + "RemediationProcedure": "For each repository that is being used, block the option to delete protected branches by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, click **Add rule**.\n 5. If you add the rule, under \"Branch name pattern\", type the branch name or pattern you want to protect.\n 6. Uncheck **Allow deletions**.\n 7. Click **Create** or **Save changes**.", + "AuditProcedure": "For each repository that is being used, verify that protected branches cannot be deleted by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn't, you are not compliant.\n 5. Ensure that **Allow deletions** is not checked.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule" + } + ] + }, + { + "Id": "1.1.18", + "Description": "Ensure any merging of code is automatically scanned for risks", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure that every pull request is required to be scanned for risks.", + "RationaleStatement": "Scanning pull requests to detect risks allows for early detection of vulnerable code and/or dependencies and helps mitigate potentially malicious code.", + "ImpactStatement": "", + "RemediationProcedure": "For every repository in use, enforce risk scanning on every pull request by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Actions**.\n 3. If the repository already has at least one workflow set up and running, click **New workflow** and go to step 5. If there are currently no workflows configured for the repository, go to the next step.\n 4. Scroll down to the \"Security\" category and click **Configure** under the workflow you want to configure or click **View all** to see all available security workflows.\n 5. On the right pane of the workflow page, click **Documentation** and follow the on-screen instructions to tailor the workflow to your needs.", + "AuditProcedure": "For each repository in use, ensure that every pull request must be scanned for risks by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Actions**.\n 3. Ensure that at least one workflow is configured to run like that: \n ```\n on:\n push:\n branches: [ \"main\" ]\n pull_request:\n branches: [ \"main\" ]\n ```\n and that it has a step that runs code scanning on the code.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.1.19", + "Description": "Ensure any changes to branch protection rules are audited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure that changes in the branch protection rules are audited.", + "RationaleStatement": "Branch protection rules should be configured on every repository. The only users who may change such rules are administrators. In a case of an attack on an administrator account or of human error on the part of an administrator, protection rules could be disabled, and thus decrease source code confidentiality as a result. It is important to track and audit such changes to prevent potential incidents as soon as possible.", + "ImpactStatement": "", + "RemediationProcedure": "Use the audit log to audit changes in branch protection rules by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Archives\" section of the sidebar, click **Logs**, then click **Audit log**.\n 4. Use the action qualifier in your query and look for **protected_branch** category. Ensure every action is reasonable and secure and investigate if not.", + "AuditProcedure": "Ensure changes in branch protection rules are audited by performing the following regularly:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Archives\" section of the sidebar, click **Logs**, then click **Audit log**.\n 4. Use the action qualifier in your query and look for **protected_branch** category. Ensure every action is reasonable and secure and is investigated if not.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches" + } + ] + }, + { + "Id": "1.1.20", + "Description": "Ensure branch protection is enforced on the default branch", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Enforce branch protection on the default and main branch.", + "RationaleStatement": "The default or main branch of repositories is considered very important, as it is eventually gets deployed to the production. Therefore it needs protection. By enforcing branch protection rules on this branch, it is secured from unwanted or unauthorized changes. It can also be protected from untested and unreviewed changes and more.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to enforce branch protection on the main branch:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Next to \"Branch protection rules\", click **Add rule**.\n 5. Under \"Branch name pattern\", type the branch name or pattern you want to protect. Ensure it applies to the main branch name.\n 6. Configure policies you want.\n 7. Click Create.", + "AuditProcedure": "Perform the following to ensure branch protection is enforced on the main branch:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Code and automation\" section of the sidebar, click **Branches**.\n 4. Under **Branch protection rules**, verify that there is a rule applied to the \"main\" or default branch.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.1", + "Description": "Ensure all public repositories contain a SECURITY.md file", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "A SECURITY.md file is a security policy file that offers instruction on reporting security vulnerabilities in a project. When someone creates an issue within a specific project, a link to the SECURITY.md file will subsequently be shown.", + "RationaleStatement": "A SECURITY.md file provides users with crucial security information. It can also serve an important role in project maintenance, encouraging users to think ahead about how to properly handle potential security issues, updates, and general security practices.", + "ImpactStatement": "", + "RemediationProcedure": "Enforce that each public repository has a SECURITY.md file by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under the repository name, click **Security**.\n 3. In the left sidebar, click **Security policy**.\n 4. Click **Start setup**.\n 5. In the new SECURITY.md file, add information about supported versions of your project and how to report a vulnerability.\n 6. At the bottom of the page, type a commit message.\n 7. Below the commit message fields, choose to create a new branch for your commit and then create a pull request.\n 8. Click **Propose file change**.", + "AuditProcedure": "Verify that each public repository has a SECURITY.md file by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under the repository name, click **Security**.\n 3. Verify that **Security policy** is enabled.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.2", + "Description": "Ensure repository creation is limited to specific members", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Limit the ability to create repositories to trusted users and teams.", + "RationaleStatement": "Restricting repository creation to trusted users and teams is recommended in order to keep the organization properly structured, track fewer items, prevent impersonation, and to not overload the version-control system. It will allow administrators easier source code tracking and management capabilities, as they will have fewer repositories to track. The process of detecting potential attacks also becomes far more straightforward, as well, since the easier it is to track the source code, the easier it is to detect malicious acts within it. Additionally, the possibility of a member creating a public repository and sharing the organization's data externally is significantly decreased.", + "ImpactStatement": "Specific users will not be permitted to create repositories.", + "RemediationProcedure": "Restrict repository creation to trusted users and teams only by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Repository creation\", unselect both options - **Public** and **Private**.\n 5. Click **Save**.", + "AuditProcedure": "Verify that only trusted users and teams can create repositories by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Repository creation\", ensure that **Public** and **Private** are not checked. This means only owners are able to create repositories.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.3", + "Description": "Ensure repository deletion is limited to specific users", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure only a limited number of trusted users can delete repositories.", + "RationaleStatement": "Restricting the ability to delete repositories protects the organization from intentional and unintentional data loss. This ensures that users cannot delete repositories or cause other potential damage — whether by accident or due to their account being hacked — unless they have the correct privileges.", + "ImpactStatement": "Certain users will not be permitted to delete repositories.", + "RemediationProcedure": "Enforce repository deletion by a few trusted and responsible users only by performing either of the following steps:\n \n\n If Your organizations > Settings > Access > Member privileges > Allow members to delete or transfer repositories for this organization is selected, allow only trusted members to have admin privileges:\n 1. In every repository, on GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings** and then in the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 3. Under \"Manage access\" use the dropdown **Role** menu to filter and search for admin members. Change their role by clicking the **Role** dropdown next to the username until there are only two trusted and qualified users with admin privileges. \n \n\n If it is not selected, allow only trusted users to become an organization owner:\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. You will see a list of the people in your organization. Click Role and select Owners. Check every member you want to change permissions to. Above the list of members, use the drop-down menu and click Change role and choose Member > change role. Do that until there are only a few trusted and qualified users with organization owner privileges. \n \n\n In any case, only members with administrator or organization owner privileges can delete repositories, regardless of your setting.", + "AuditProcedure": "Verify that only a limited number of trusted users can delete repositories by performing either of the following steps:\n \n\n If Your organizations > Settings > Access > Member privileges > Allow members to delete or transfer repositories for this organization is selected, verify that every admin member is trusted by you:\n 1. In every repository, on GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings** and then in the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 3. Under \"Manage access\" use the dropdown **Role** menu to filter and search for admin members. Verify that there are only two of them and that they are trusted and qualified. \n \n\n If it is not selected, verify that every organization owner is trusted by you:\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. You will see a list of the people in your organization. Click Role and select Owners. Verify that there are only a few of them and that they are trusted and qualified. \n \n\n In any case, only members with administrator or organization owner privileges can delete repositories, regardless of your setting.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.4", + "Description": "Ensure issue deletion is limited to specific users", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure only trusted and responsible users can delete issues.", + "RationaleStatement": "Issues are a way to keep track of things happening in repositories, such as setting new milestones or requesting urgent fixes. Deleting an issue is not a benign activity, as it might harm the development workflow or attempt to hide malicious behavior. Because of this, it should be restricted and allowed only by trusted and responsible users.", + "ImpactStatement": "Certain users will not be permitted to delete issues.", + "RemediationProcedure": "Restrict issue deletion to a few trusted and responsible users only by performing either of the following steps:\n \n\n If Your organizations > Settings > Access > Member privileges > Allow members to delete issues for this organization is selected, allow only trusted members to have admin privileges:\n 1. In every repository, on GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings** and then in the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 3. Under \"Manage access\" use the dropdown **Role** menu to filter and search for admin members. Change their role by clicking the **Role** dropdown next to the username until there are only two trusted and qualified users with admin privileges.\n \n\n If it is not selected, allow only trusted users to become an organization owner:\n 1. In the top right corner of GitHub.com, click your profile photo, then click Your organizations.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. You will see a list of the people in your organization. Click **Role** and select **Owners**. Check every member you want to change permissions to. Above the list of members, use the drop-down menu and click **Change role** and choose Member > change role. Do that until there are only a few trusted and qualified users with organization owner privileges.\n \n\n In any case, only members with administrator or organization owner privileges can delete issues, regardless of your setting.", + "AuditProcedure": "Verify that only a limited number of trusted users can delete issues by performing either of the following steps:\n \n\n If Your organizations > Settings > Access > Member privileges > Allow members to delete issues for this organization is selected, verify that every admin member is trusted by you:\n 1. In every repository, on GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings** and then in the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 3. Under \"Manage access\" use the dropdown **Role** menu to filter and search for admin members. Verify that there are only two of them and that they are trusted and qualified.\n \n\n If it is not selected, verify that every organization owner is trusted by you:\n 1. In the top right corner of GitHub.com, click your profile photo, then click Your organizations.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. You will see a list of the people in your organization. Click **Role** and select **Owners**. Verify that there are only a few of them and that they are trusted and qualified.\n \n\n In any case, only members with administrator or organization owner privileges can delete issues, regardless of your setting.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.5", + "Description": "Ensure all copies (forks) of code are tracked and accounted for", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Track every fork of code and ensure it is accounted for.", + "RationaleStatement": "A fork is a copy of a repository. On top of being a plain copy, any updates to the original repository itself can be pulled and reflected by the fork under certain conditions. A large number of repository copies (forks) become difficult to manage and properly secure. New and sensitive changes can often be pushed into a critical repository without developer knowledge of an updated copy of the very same repository. If there is no limit on doing this, then it is recommended to track and delete copies of organization repositories as needed.", + "ImpactStatement": "Disabling forks completely may slow down the development process as more actions will be necessary to take in order to fork a repository.", + "RemediationProcedure": "Track forks and examine them by performing the following on a regular basis:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Insights**.\n 3. In the left sidebar, click **Forks**.\n 4. Examine the forks listed there.", + "AuditProcedure": "Verify that the following steps are done regularly to track and examine forks:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Insights**.\n 3. In the left sidebar, click **Forks**.\n 4. Examine the forks listed there.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.6", + "Description": "Ensure all code projects are tracked for changes in visibility status", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure every change in visibility of projects is tracked.", + "RationaleStatement": "Visibility of projects determines who can access a project and/or fork it: anyone, designated users, or only members of the organization. If a private project becomes public, this may point to a potential attack, which can ultimately lead to data loss, the leaking of sensitive information, and finally to a supply chain attack. It is crucial to track these changes in order to prevent such incidents.", + "ImpactStatement": "", + "RemediationProcedure": "Track every change in project visibility and investigate if suspicious behavior occurs, by performing the following regularly:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Archives\" section of the sidebar, click **Logs**, then click **Audit log**.\n 4. Use the **repo** qualifier in your query and look for **access** category. Ensure every change is reasonable and secure and investigate if it is not.", + "AuditProcedure": "Ensure that every change in project visibility is tracked and investigated, by performing the following regularly:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Archives\" section of the sidebar, click **Logs**, then click **Audit log**.\n 4. Use the **repo** qualifier in your query and look for **access** category. Ensure every change is reasonable and secure and is investigated if it is not.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.2.7", + "Description": "Ensure inactive repositories are reviewed and archived periodically", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Track inactive repositories and remove them periodically.", + "RationaleStatement": "Inactive repositories (i.e., no new changes introduced for a long period of time) can enlarge the surface of a potential attack or data leak. These repositories are more likely to be improperly managed, and thus could possibly be accessed by a large number of users in an organization.", + "ImpactStatement": "Bug fixes and deployment of necessary changes could prove complicated for archived repositories.", + "RemediationProcedure": "Perform the following to review all inactive repositories and archive them periodically:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click on your organization name and then on **repositories**.\n 3. Ensure every repository listed has been active in the last 3 to 6 months. Every repository that isn't active you should either review or archive by performing the next steps:\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. Under \"Danger Zone\", click **Archive this repository**.\n 4. Read the warnings.\n 5. Type the name of the repository you want to archive.\n 6. Click **I understand the consequences, archive this repository**.", + "AuditProcedure": "Perform the following to ensure that all the repositories in the organization are active, and those that are not reviewed or archived:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click on your organization name and then on **repositories**.\n 3. Ensure every repository listed has been active in the last 3 to 6 months. If it's not, then ensure it is archived or reviewed regularly.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.1", + "Description": "Ensure inactive users are reviewed and removed periodically", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Track inactive user accounts and periodically remove them.", + "RationaleStatement": "User accounts that have been inactive for a long period of time are enlarging the surface of attack. Inactive users with high-level privileges are of particular concern, as these accounts are more likely to be targets for attackers. This could potentially allow access to large portions of an organization should such an attack prove successful. It is recommended to remove them as soon as possible in order to prevent this.", + "ImpactStatement": "", + "RemediationProcedure": "If you have GitHub AE, perform the following to review inactive user accounts and remove them:\n \n\n 1. From an administrative account on GitHub AE, in the upper-right corner of any page, click the rocket icon.\n 2. If you're not already on the \"Site admin\" page, in the upper-left corner, click **Site admin**.\n 3. In the left sidebar, click **Dormant users**.\n 4. Find the users listed there under **Your organizations** > your organization > **People** and select them.\n 5. Click **Remove from organization** and **Remove members**.\n \n\n If you have GitHub Enterprise Cloud, perform the following:\n \n\n 1. In the top-right corner of GitHub.com, click your profile photo, then click **Your enterprises**.\n 2. In the list of enterprises, click the enterprise you want to view.\n 3. In the enterprise account sidebar, click **Compliance**.\n 4. To download your Dormant Users (beta) report as a CSV file, under \"Other\", click **Download**.\n 5. Find the users listed in the file under **Your organizations** > your organization > **People** and select them.\n 6. Click **Remove from organization** and **Remove members**.", + "AuditProcedure": "If you have GitHub AE, verify that all user accounts are active by performing the following:\n \n\n 1. From an administrative account on GitHub AE, in the upper-right corner of any page, click the rocket icon.\n 2. If you're not already on the \"Site admin\" page, in the upper-left corner, click **Site admin**.\n 3. In the left sidebar, click **Dormant users**.\n 4. Verify that the list is empty.\n \n\n If you have GitHub Enterprise Cloud, perform the following:\n \n\n 1. In the top-right corner of GitHub.com, click your profile photo, then click **Your enterprises**.\n 2. In the list of enterprises, click the enterprise you want to view.\n 3. In the enterprise account sidebar, click **Compliance**.\n 4. To download your Dormant Users (beta) report as a CSV file, under \"Other\", click **Download**.\n 5. Verify that there are no users listed.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.2", + "Description": "Ensure team creation is limited to specific members", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Limit ability to create teams to trusted and specific users.", + "RationaleStatement": "The ability to create new teams should be restricted to specific members in order to keep the organization orderly and ensure users have access to only the lowest privilege level necessary. Teams typically inherit permissions from their parent team, thus if base permissions are less restricted and any user has the ability to create a team, a permission leverage could occur in which certain data is made available to users who should not have access to it. Such a situation could potentially lead to the creation of shadow teams by an attacker. Restricting team creation will also reduce additional clutter in the organizational structure, and as a result will make it easier to track changes and anomalies.", + "ImpactStatement": "Only specific users will be able to create new teams.", + "RemediationProcedure": "For every organization, limit team creation to specific, trusted users by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Team creation rules\", deselect **Allow members to create teams**.\n 5. Click **Save**.", + "AuditProcedure": "For every organization, ensure that team creation is limited to specific, trusted users by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Team creation rules\", verify that **Allow members to create teams** is not selected.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.3", + "Description": "Ensure minimum number of administrators are set for the organization", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure the organization has a minimum number of administrators.", + "RationaleStatement": "Organization administrators have the highest level of permissions, including the ability to add/remove collaborators, create or delete repositories, change branch protection policy, and convert to a publicly-accessible repository. Due to the permissive access granted to an organization administrator, it is highly recommended to keep the number of administrator accounts as minimal as possible.", + "ImpactStatement": "", + "RemediationProcedure": "Set the minimum number of administrators in your organization by performing the following:\n \n\n 1. In the top right corner of GitHub, click your profile photo, then click **Your profile**.\n 2. On the left side of your profile page, under \"Organizations\", click the icon for your organization.\n 3. Under your organization name, click **People**. \n 4. In the Role drop-down, choose **Owners**.\n 5. Select the person or people you'd like to remove from owner role.\n 6. Above the list of members, use the drop-down menu and click Change role.\n 7. Select **Member**, then click **Change role**.", + "AuditProcedure": "Verify the minimum number of administrators in your organization by performing the following:\n \n\n 1. In the top right corner of GitHub, click your profile photo, then click **Your profile**.\n 2. On the left side of your profile page, under \"Organizations\", click the icon for your organization.\n 3. Under your organization name, click **People**. \n 4. In the Role drop-down, choose **Owners**.\n 5. If there are minimum number of members in the list, you are compliant.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.4", + "Description": "Ensure Multi-Factor Authentication (MFA) is required for contributors of new code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Require collaborators from outside the organization to use Multi-Factor Authentication (MFA) in addition to a standard user name and password when authenticating to the source code management platform.", + "RationaleStatement": "By default every user authenticates within the system by password only. If the password of a user is compromised, however, the user account and every repository to which they have access are in danger of data loss, malicious code commits, and data theft. It is therefore recommended that each user has Multi-Factor Authentication enabled. This adds an additional layer of protection to ensure the account remains secure even if the user's password is compromised.", + "ImpactStatement": "A member without enabled Multi-Factor Authentication cannot contribute to the project. They must enable Multi-Factor Authentication a before they can contribute any code.", + "RemediationProcedure": "For each repository in use, enforce Multi-Factor Authentication is the only way to authenticate for contributors, by doing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Under \"Authentication\", select **Require two-factor authentication for everyone in your organization**, then click **Save**.", + "AuditProcedure": "For each repository in use, verify that Multi-Factor Authentication is enforced for contributors and is the only way to authenticate, by doing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Under \"Authentication\", check if **Require two-factor authentication for everyone in your organization** is checked. If so, you are compliant.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.5", + "Description": "Ensure the organization is requiring members to use Multi-Factor Authentication (MFA)", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Require members of the organization to use Multi-Factor Authentication (MFA) in addition to a standard user name and password when authenticating to the source code management platform.", + "RationaleStatement": "By default every user authenticates within the system by password only. If the password of a user is compromised, however, the user account and every repository to which they have access are in danger of data loss, malicious code commits, and data theft. It is therefore recommended that each user has Multi-Factor Authentication enabled. This adds an additional layer of protection to ensure the account remains secure even if the user's password is compromised.", + "ImpactStatement": "Members will be removed from the organization if they don't have Multi-Factor Authentication already enabled. If this is the case, it is recommended that an invitation be sent to reinstate the user's access and former privileges. They must enable Multi-Factor Authentication to accept the invitation.", + "RemediationProcedure": "For every organization that exists in your GitHub platform, enforce Multi-Factor Authentication and define it as the only way to authenticate, by doing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Under \"Authentication\", select **Require two-factor authentication for everyone in your organization**, then click **Save**.\n 5. If prompted, read the information about members and outside collaborators who will be removed from the organization. Type your organization's name to confirm the change, then click **Remove members & require two-factor authentication**.", + "AuditProcedure": "For every organization that exists in your GitHub platform, verify that Multi-Factor Authentication is enforced and is the only way to authenticate, by doing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Under \"Authentication\", check if **Require two-factor authentication for everyone in your organization** is checked. If so, you are compliant.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.6", + "Description": "Ensure new members are required to be invited using company-approved email", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Existing members of an organization can invite new members to join, however new members must only be invited with their company-approved email.", + "RationaleStatement": "Ensuring new members of an organization have company-approved email prevents existing members of the organization from inviting arbitrary new users to join. Without this verification, they can invite anyone who is using the organization's version control system or has an active email account, thus allowing outside users (and potential threat actors) to easily gain access to company private code and resources. This practice will subsequently reduce the chance of human error or typos when inviting a new member.", + "ImpactStatement": "Existing members would not be able to invite new users who do not have a company-approved email address.", + "RemediationProcedure": "For each organization, allow only users with company-approved email to be invited. If a user was invited without company-approved email, perform the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. On the People tab, click **Invitations**. Next to the username or email address of the person whose invitation you'd like to cancel, click **Edit invitation**.\n 4. To cancel the user's invitation to join your organization, click **Cancel invitation**.", + "AuditProcedure": "For each organization in use, verify for every invitation that the invited email address is company-approved by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Click the name of your organization and under your organization name, click **People**.\n 3. On the People tab, click **Invitations**. Verify that each invitation email is company approved by your company.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.7", + "Description": "Ensure two administrators are set for each repository", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Ensure every repository has two users with administrative permissions.", + "RationaleStatement": "Repository administrators have the highest permissions to said repository. These include the ability to add/remove collaborators, change branch protection policy, and convert to a publicly-accessible repository. Due to the liberal access granted to a repository administrator, it is highly recommended that only two contributors occupy this role.", + "ImpactStatement": "Removing administrative users from a repository would result in them losing high-level access to that repository.", + "RemediationProcedure": "For every repository in use, set two administrators by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 4. Under **Manage access**, find the team or person whose you'd like to revoke admin permissions, then select the Role drop-down and click a new role.", + "AuditProcedure": "For every repository in use, verify there are two administrators by performing the following:\n \n\n 1. On GitHub, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Collaborators & teams**.\n 4. Under **Manage access**, verify that there are only 2 members with Admin permission.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.8", + "Description": "Ensure strict base permissions are set for repositories", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Base permissions define the permission level automatically granted to all organization members. Define strict base access permissions for all of the repositories in the organization, including new ones.", + "RationaleStatement": "Defining strict base permissions is the best practice in every role-based access control (RBAC) system. If the base permission is high — for example, \"write\" permission — every member of the organization will have \"write\" permission to every repository in the organization. This will apply regardless of the specific permissions a user might need, which generally differ between organization repositories. The higher the permission, the higher the risk for incidents such as bad code commit or data breach. It is therefore recommended to set the base permissions to the strictest level possible.", + "ImpactStatement": "Users might not be able to access organization repositories or perform some acts as commits. These specific permissions should be granted individually for each user or team, as needed.", + "RemediationProcedure": "Set strict base permissions for the organization repositories with the next steps:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Base permissions\", use the drop-down to select new base permissions - \"Read\" or \"None\".\n 5. Review the changes. To confirm, click **Change default permission to PERMISSION**.", + "AuditProcedure": "Verify that strict base permissions are set for the organization repositories by doing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Access\" section of the sidebar, click **Member privileges**.\n 4. Under \"Base permissions\", verify that it is set to \"Read\" or \"None\". If it does, you are compliant.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.9", + "Description": "Ensure an organization’s identity is confirmed with a “Verified” badge", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Confirm the domains an organization owns with a \"Verified\" badge.", + "RationaleStatement": "Verifying the organization's domain gives developers assurance that a given domain is truly the official home for a public organization. Attackers can pretend to be an organization and steal information via a faked/spoof domain, therefore the use of a \"Verified\" badge instills more confidence and trust between developers and the open-source community.", + "ImpactStatement": "", + "RemediationProcedure": "Only if you have an enterprise account, verify the organization's domains and secure a \"Verified\" badge next to its name by performing the following:\n \n\n 1. In the top-right corner of GitHub.com, click your profile photo, then click **Your enterprises**.\n 2. In the list of enterprises, click the enterprise you want to view. Then in the enterprise account sidebar, click **Settings**.\n 3. Under \"Settings\", click **Verified & approved domains**.\n 4. Click **Add a domain**.\n 5. In the domain field, type the domain you'd like to verify, then click **Add domain**.\n 6. Follow the instructions under **Add a DNS TXT record** to create a DNS TXT record with your domain hosting service. Wait for your DNS configuration to change, which may take up to 72 hours. You can confirm your DNS configuration has changed by running the `dig` command on the command line, replacing ENTERPRISE-ACCOUNT with the name of your enterprise account, and example.com with the domain you'd like to verify. You should see your new TXT record listed in the command output.\n ```\n dig _github-challenge-ENTERPRISE-ACCOUNT.DOMAIN-NAME +nostats +nocomments +nocmd TXT\n ```\n 7. After confirming your TXT record is added to your DNS, follow steps one through three above to navigate to your enterprise account's approved and verified domains.\n 8. To the right of the domain that's pending verification, click the 3-dots, then click **Continue verifying**. Click **Verify**.\n 9. Optionally, after the \"Verified\" badge is visible on your organizations' profiles, delete the TXT entry from the DNS record at your domain hosting service.", + "AuditProcedure": "Only if you have an enterprise account, view the enterprise organization profile page and ensure it has a \"Verified\" badge in it.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/organizations/managing-organization-settings/verifying-or-approving-a-domain-for-your-organization" + } + ] + }, + { + "Id": "1.3.10", + "Description": "Ensure Source Code Management (SCM) email notifications are restricted to verified domains", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Restrict the Source Code Management (SCM) organization's email notifications to approved domains only.", + "RationaleStatement": "Restricting Source Code Management email notifications to verified domains only prevents data leaks, as personal emails and custom domains are more prone to account takeover via DNS hijacking or password breach.", + "ImpactStatement": "Only members with approved email would be able to receive Source Code Management notifications.", + "RemediationProcedure": "Only if you have an enterprise account, restrict Source Code Management email notifications to approved domains only by performing the following:\n \n\n 1. In the top-right corner of GitHub.com, click your profile photo, then click **Your enterprises**.\n 2. In the list of enterprises, click the enterprise you want to view. Then in the enterprise account sidebar, click **Settings**.\n 3. Under \"Settings\", click **Verified & approved domains**.\n 4. Under \"Notification preferences\", select **Restrict email notifications to only approved or verified domains**.\n 5. Click **Save**.", + "AuditProcedure": "Only if you have an enterprise account, ensure Source Code Management email notifications are restricted to approved domains only by performing the following:\n \n\n 1. In the top-right corner of GitHub.com, click your profile photo, then click **Your enterprises**.\n 2. In the list of enterprises, click the enterprise you want to view. Then in the enterprise account sidebar, click **Settings**.\n 3. Under \"Settings\", click **Verified & approved domains**.\n 4. Under \"Notification preferences\", verify that **Restrict email notifications to only approved or verified domains** is selected.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.11", + "Description": "Ensure an organization provides SSH certificates", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "As an organization, become an SSH Certificate Authority and provide SSH keys for accessing repositories.", + "RationaleStatement": "There are two ways for remotely working with Source Code Management: via HTTPS, which requires authentication by user/password, or via SSH, which requires the use of SSH keys. SSH authentication is better in terms of security; key creation and distribution, however, must be done in a secure manner. This can be accomplished by implementing SSH certificates, which are used to validate the server's identity. A developer will not be able to connect to a Git server if its key cannot be verified by the SSH Certificate Authority (CA) server.\n As an organization, one can verify the SSH certificate signature used to authenticate if a CA is defined and used. This ensures that only verified developers can access organization repositories, as their SSH key will be the only one signed by the CA certificate. This reduces the risk of misuse and malicious code commits.", + "ImpactStatement": "Members with unverified keys will not be able to clone organization repositories. Signing, certification, and verification might also slow down the development process.", + "RemediationProcedure": "Only if you have an enterprise account, deploy an SSH Certificate Authority server and configure it to provide an SSH certificate with which to sign keys by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. To the right of \"SSH Certificate Authorities\", click **New CA**.\n 5. Under \"Key,\" paste your public SSH key.\n 6. Click **Add CA**.\n 7. Click **Save**.", + "AuditProcedure": "Only if you have an enterprise account, verify that the enterprise organization has an SSH Certificate Authority server and provides an SSH certificate with which to sign keys by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Verify that there's an SSH certificate authority listed there.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.3.12", + "Description": "Ensure Git access is limited based on IP addresses", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Limit Git access based on IP addresses by having a allowlist of IP addresses from which connection is possible.", + "RationaleStatement": "Allowing access to Git repositories (source code) only from specific IP addresses adds yet another layer of restriction and reduces the risk of unauthorized connection to the organization's assets. This will prevent attackers from accessing Source Code Management (SCM), as they would first need to know the allowed IP addresses to gain access to them.", + "ImpactStatement": "Only members with allowlisted IP addresses will be able to access the organization's Git repositories.", + "RemediationProcedure": "Only if you have an enterprise account, create an IP allowlist and forbid all other IPs from accessing the source code by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. At the bottom of the \"IP allow list\" section, enter an IP address, or a range of addresses in CIDR notation. Optionally, enter a description of the allowed IP address or range.\n 5. Click **Add**.\n 6. After that, under \"IP allow list\", select **Enable IP allow list**.\n 7. Click **Save**.", + "AuditProcedure": "Only if you have an enterprise account, in every organization of yours, ensure access is allowed only by IP allowlist, and that access is forbidden for all other IPs by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Authentication security**.\n 4. Verify that there's an IP address, or a range of addresses in CIDR notation listed. Also verify that **Enable IP allow list** is selected.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-allowed-ip-addresses-for-your-organization" + } + ] + }, + { + "Id": "1.3.13", + "Description": "Ensure anomalous code behavior is tracked", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Track code anomalies.", + "RationaleStatement": "Carefully analyze any code anomalies within the organization. For example, a code anomaly could be a push made outside of working hours. Such a code push has a higher likelihood of being the result of an attack, as most if not all members of the organization would likely be outside the office. Another example is an activity that exceeds the average activity of a particular user.\n Tracking and auditing such behaviors creates additional layers of security and can aid in early detection of potential attacks.", + "ImpactStatement": "", + "RemediationProcedure": "For every repository in use, track and investigate anomalous code behavior and activity.", + "AuditProcedure": "For every repository in use, ensure code anomalies relevant to the organization are promptly investigated.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.4.1", + "Description": "Ensure administrator approval is required for every installed application", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure an administrator approval is required when installing applications.", + "RationaleStatement": "Applications are typically automated integrations that improve the workflow of an organization. They are written by third-party developers, and therefore should be validated before using in case they're malicious or not trustable. Because administrators are expected to be the most qualified and trusted members of the organization, they should review the applications being installed and decide whether they are both trusted and necessary.", + "ImpactStatement": "Applications will not be installed without administrator approval.", + "RemediationProcedure": "Require an administrator approval for every installed application:\n \n\n a. For GitHub Apps, you are compliant by default. That is because by default only organization owners and administrators can install them.\n \n\n b. For OAuth Apps, perform the following:\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Third-party Access\" section of the sidebar, click **OAuth application policy**.\n 4. Under \"Third-party application access policy\", click **Setup application access restrictions**.\n 5. After you review the information about third-party access restrictions, click **Restrict third-party application access**.", + "AuditProcedure": "Verify that applications are installed only after receiving administrator approval:\n \n\n a. For GitHub Apps, you are compliant by default. That is because by default only organization owners and administrators can install them.\n \n\n b. For OAuth Apps, perform the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Third-party Access\" section of the sidebar, click **OAuth application policy**.\n 4. Under \"Third-party application access policy\" verify that the policy status is **Access restricted**.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.4.2", + "Description": "Ensure stale applications are reviewed and inactive ones are removed", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure stale (inactive) applications are reviewed and removed if no longer in use.", + "RationaleStatement": "Applications that have been inactive for a long period of time are enlarging the surface of attack for data leaks. They are more likely to be improperly managed, and could possibly be accessed by third-party developers as a tool for collecting internal data of the organization or repository in which they are installed. It is important to remove these inactive applications as soon as possible.", + "ImpactStatement": "", + "RemediationProcedure": "Review all stale applications and periodically remove them.", + "AuditProcedure": "Verify that all the applications in the organization are actively used, and remove those that are no longer in use.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.4.3", + "Description": "Ensure the access granted to each installed application is limited to the least privilege needed", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure installed application permissions are limited to the lowest privilege level required.", + "RationaleStatement": "Applications are typically automated integrations that can improve the workflow of an organization. They are written by third-party developers, and therefore should be reviewed carefully before use. It is recommended to use the \"least privilege\" principle, granting applications the lowest level of permissions required. This may prevent harm from a potentially malicious application with unnecessarily high-level permissions leaking data or modifying source code.", + "ImpactStatement": "", + "RemediationProcedure": "Grant permissions to applications by the \"least privilege\" principle, meaning the lowest possible permission necessary:\n \n\n a. For GitHub Apps, perform the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Integrations\" section of the sidebar, click **GitHub Apps**.\n 4. Next to every GitHub App, click **Configure**.\n 5. Review the GitHub App's permissions and repository access. Edit the permissions granted to the least possible. For example, restrict the number of repositories the App can access.\n 6. Click **Save**.", + "AuditProcedure": "Verify that each installed application has the least privilege needed:\n \n\n a. For GitHub Apps, perform the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the \"Integrations\" section of the sidebar, click **GitHub Apps**.\n 4. Next to every GitHub App, click **Configure**.\n 5. Review the GitHub App's permissions and repository access. Verify that the App permissions are the least possible and that it can access only necessary repositories.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.4.4", + "Description": "Ensure only secured webhooks are used", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use only secured webhooks in the source code management platform.", + "RationaleStatement": "A webhook is an event listener, attached to critical and sensitive parts of the software delivery process. It is triggered by a list of events (such as a new code being committed), and when triggered, the webhook sends out a notification with some payload to specific internet endpoints. Since the payload of the webhook contains sensitive organization data, it's important all webhooks are directed to an endpoint (URL) protected by SSL verification (HTTPS). This helps ensure that the data sent is delivered to securely without any man-in-the-middle, who could easily access and even alter the payload of the request.", + "ImpactStatement": "Perform the following to ensure all webhooks used are secured (HTTPS):\n \n\n 1. Navigate to your organization or repository and select **Settings**.\n 2. Select **Webhooks** on the side menu.\n 3. Verify that each webhook URL starts with 'https'.", + "RemediationProcedure": "Perform the following to secure all webhooks used(over HTTPS):\n \n\n 1. Navigate to your organization or repository and select **Settings**.\n 2. Select **Webhooks** on the side menu.\n 3. Find the webhooks that starts with 'http' and not 'https'.\n 4. Ensure the endpoint (URL) of the webhook listens to secured port (443) and uses certificate.\n 5. Click **Edit**.\n 6. Change the payload URL to https and ensure **Enable SSL verification** is checked.\n 7. Click **Update webhook**.", + "AuditProcedure": "Perform the following to secure all webhooks used(over HTTPS):\n \n\n 1. Navigate to your organization or repository and select **Settings**.\n 2. Select **Webhooks** on the side menu.\n 3. Ensure all webhooks starts with 'https'.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.5.1", + "Description": "Ensure scanners are in place to identify and prevent sensitive data in code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent sensitive data in code, such as confidential ID numbers, passwords, etc.", + "RationaleStatement": "Having sensitive data in the source code makes it easier for attackers to maliciously use such information. In order to avoid this, designate scanners to identify and prevent the existence of sensitive data in the code.", + "ImpactStatement": "", + "RemediationProcedure": "For every repository in use, designate scanners to identify and prevent sensitive data in code by performing the following (enterprise only):\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Code security and analysis**.\n 4. Scroll down to the bottom of the page and click **Enable** for secret scanning.", + "AuditProcedure": "For every repository in use, verify that scanners are set to identify and prevent the existence of sensitive data in code by performing the following (enterprise only):\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the \"Security\" section of the sidebar, click **Code security and analysis**.\n 4. Scroll down to the bottom of the page. If you see a **Disable** button, it means that secret scanning is already enabled for the repository.", + "AdditionalInformation": "By January 2023, this feature is supposed to be open to all plans. Until then it is only for enterprise users.", + "References": "" + } + ] + }, + { + "Id": "1.5.2", + "Description": "Ensure scanners are in place to secure Continuous Integration (CI) pipeline instructions", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent misconfigurations and insecure instructions in CI pipelines", + "RationaleStatement": "Detecting and fixing misconfigurations or insecure instructions in CI pipelines decreases the risk for a successful attack through or on the CI pipeline. The more secure the pipeline, the less risk there is for potential exposure of sensitive data, a deployment being compromised, or external access mistakenly being granted to the CI infrastructure or the source code.", + "ImpactStatement": "", + "RemediationProcedure": "Set a CI instructions scanning tool to identify and prevent misconfigurations and insecure instructions and scans all CI pipelines.", + "AuditProcedure": "Verify that a CI instructions scanning tool is set to identify and prevent misconfigurations and insecure instructions and that it scans all CI pipelines.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.5.3", + "Description": "Ensure scanners are in place to secure Infrastructure as Code (IaC) instructions", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent misconfigurations or insecure instructions in Infrastructure as Code (IaC) files, such as Terraform files.", + "RationaleStatement": "Detecting and fixing misconfigurations and/or insecure instructions in IaC (Infrastructure as Code) files decreases the risk for data leak or data theft. It is important to secure IaC instructions in order to prevent further problems of deployment, exposed assets, or improper configurations, which can ultimately lead to easier ways to attack and steal organization data.", + "ImpactStatement": "", + "RemediationProcedure": "For every repository that holds IaC instructions files, set a scanning tool to identify and prevent misconfigurations and insecure instructions.", + "AuditProcedure": "For every repository that holds IaC instructions files, verify that a scanning tool is set to identify and prevent misconfigurations and insecure instructions.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.5.4", + "Description": "Ensure scanners are in place for code vulnerabilities", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent known open source vulnerabilities in the code.", + "RationaleStatement": "Open source code blocks are used a lot in developed software. This has its own advantages, but it also has risks. Because the code is open for everyone, it means that attackers can publish or add malicious code to these open-source code blocks, or use their knowledge to find vulnerabilities in an existing code. Detecting and fixing such code vulnerabilities, by SCA (Software Composition Analysis) prevents insecure flaws from reaching production. It gives another opportunity for developers to secure the source code before it is deployed in production, where it is far more exposed and vulnerable to attacks.", + "ImpactStatement": "", + "RemediationProcedure": "For every repository that is in use, set a scanning tool to identify and prevent code vulnerabilities by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under the repository name, click **Security**.\n 3. To the right of \"Code scanning alerts\", click **Set up code scanning**.\n 4. Under \"Get started with code scanning\", click Set up this workflow on a workflow of your choice.\n 5. To customize how code scanning scans your code, edit the workflow.\n 6. Use the **Start commit** drop-down and type a commit message.\n 7. Choose whether you'd like to commit directly to the default branch or create a new branch and start a pull request.\n 8. Click **Commit new file** or **Propose new file**.", + "AuditProcedure": "For every repository that is in use, verify that a scanning tool is set to identify and prevent code vulnerabilities by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under the repository name, click **Security**.\n 3. Verify that \"Code scanning alerts\" is **Enabled** or that there is a workflow that scans your code.", + "AdditionalInformation": "All public repositories in all plans can use code scanning in GitHub. In private repositories, only GitHub Enterprise can use code scanning.", + "References": "" + } + ] + }, + { + "Id": "1.5.5", + "Description": "Ensure scanners are in place for open-source vulnerabilities in used packages", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect, prevent and monitor known open-source vulnerabilities in packages that are being used.", + "RationaleStatement": "Open-source vulnerabilities might exist before one starts to use a package, but they are also discovered over time. New attacks and vulnerabilities are announced every now and then. It is important to keep track of these and to monitor whether the dependencies used are affected by the recent vulnerability. Detecting and fixing those packages' vulnerabilities decreases the attack surface within deployed and running applications that use such packages. It prevents security flaws from reaching the production environment which could eventually lead to a security breach.", + "ImpactStatement": "", + "RemediationProcedure": "Set scanners that will monitor, identify, and prevent open-source vulnerabilities in packages by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**. In the \"Security\" section of the sidebar, click **Code security and analysis**.\n 3. Under \"Code security and analysis\", to the right of Dependabot alerts, click **Disable all** or **Enable all**.\n 4. Check the **Enable by default for new repositories** option and then click **Enable Dependabot alerts**.\n \n\n It is also recommended to use another additional solution for package scanning because GitHub doesn't always recognize the vulnerabilities.", + "AuditProcedure": "Verify that scanners are set to monitor, identify, and prevent open-source vulnerabilities in packages by performing the following:\n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**. In the \"Security\" section of the sidebar, click **Code security and analysis**.\n 3. Verify that the Dependabot alerts is enabled and that **Enable by default for new repositories** is checked.\n \n\n It is also recommended to verify that you're using another additional solution for package scanning because GitHub doesn't always recognize the vulnerabilities.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "1.5.6", + "Description": "Ensure scanners are in place for open-source license issues in used packages", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "1.5", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect open-source license problems in used dependencies and fix them.", + "RationaleStatement": "A software license is a legal document that establishes several key conditions between a software company or developer and a user in order to allow the use of software. Software licenses have the potential to create code dependencies. Not following the conditions in the software license can also lead to lawsuits. When using packages with a software license, especially commercial ones (which are the most permissive), it is important to verify what is allowed by that license in order to be protected against lawsuits.", + "ImpactStatement": "", + "RemediationProcedure": "Designate a license scanning tool to identify open-source license problems and fix them and scan every package you use.", + "AuditProcedure": "Ensure a license scanning tool is set up to identify open-source license problems and that every package you use is scanned by it.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.1", + "Description": "Ensure each pipeline has a single responsibility", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Ensure each pipeline has a single responsibility in the build process.", + "RationaleStatement": "Build pipelines generally have access to multiple secrets depending on their purposes. There are, for example, secrets of the test environment for the test phase, repository and artifact credentials for the build phase, etc. Limiting access to these credentials/secrets is therefore recommended by dividing pipeline responsibilities, as well as having a dedicated pipeline for each phase with the lowest privilege instead of a single pipeline for all. This will ensure that any potential damage caused by attacks on a workflow will be limited.", + "ImpactStatement": "", + "RemediationProcedure": "Divide each multi-responsibility pipeline into multiple pipelines, each having a single responsibility with the least privilege. Additionally, create all new pipelines with a sole purpose going forward.", + "AuditProcedure": "For each pipeline, ensure it has only one responsibility in the build process.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs" + } + ] + }, + { + "Id": "2.1.2", + "Description": "Ensure all aspects of the pipeline infrastructure and configuration are immutable", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure the pipeline orchestrator and its configuration are immutable.", + "RationaleStatement": "An immutable infrastructure is one that cannot be changed during execution of the pipeline. This can be done, for example, by using Infrastructure as Code for configuring the pipeline and the pipeline environment. Utilizing such infrastructure creates a more predictable environment because updates will require re-deployment to prevent any previous configuration from interfering. Because it is dependent on automation, it is easier to revert changes. Testing code is also simpler because it is based on virtualization. Most importantly, an immutable pipeline infrastructure ensures that a potential attacker seeking to compromise the build environment itself would not be able to do so if the orchestrator, its configuration, and any other component cannot be changed. Verifying that all aspects of the pipeline infrastructure and configuration are immutable therefore keeps them safe from malicious tampering attempts.", + "ImpactStatement": "", + "RemediationProcedure": "Use an immutable pipeline orchestrator and ensure that its configuration and all other aspects of the built environment are immutable, as well.", + "AuditProcedure": "Verify that the pipeline orchestrator, its configuration, and all other aspects of the build environment are immutable.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.3", + "Description": "Ensure the build environment is logged", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Keep build logs of the build environment detailing configuration and all activity within it. Also, consider to store them in a centralized organizational log store.", + "RationaleStatement": "Logging the environment is important for two primary reasons: one, for debugging and investigating the environment in case of a bug or security incident; and two, for reproducing the environment easily when needed. Storing these logs in a centralized organizational log store allows the organization to generate useful insights and identify anomalies in the build process faster.", + "ImpactStatement": "", + "RemediationProcedure": "Keep logs of the build environment. For example, use the .buildinfo file for Debian build workers. Also, store the logs in a centralized organizational log store.", + "AuditProcedure": "Verify that the build environment is logged and stored in a centralized organizational log store.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.4", + "Description": "Ensure the creation of the build environment is automated", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Automate the creation of the build environment.", + "RationaleStatement": "Automating the deployment of the build environment reduces the risk for human mistakes — such as a wrong configuration or exposure of sensitive data — because it requires less human interaction and intervention. It also eases re-deployment of the environment. It is best to automate with Infrastructure as Code because it offers more control over changes made to the environment creation configuration and stores to a version control platform.", + "ImpactStatement": "", + "RemediationProcedure": "Automate the deployment of the build environment.", + "AuditProcedure": "Verify that the deployment of the build environment is automated and can be easily redeployed.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.5", + "Description": "Ensure access to build environments is limited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Restrict access to the build environment (orchestrator, pipeline executor, their environment, etc.) to trusted and qualified users only.", + "RationaleStatement": "A build environment contains sensitive data such as environment variables, secrets, and the source code itself. Any user that has access to this environment can make changes to the build process, including changes to the code within it. Restricting access to the build environment to trusted and qualified users only will reduce the risk for mistakes such as exposure of secrets or misconfiguration. Limiting access also reduces the number of accounts that are vulnerable to hijacking in order to potentially harm the build environment.", + "ImpactStatement": "Reducing the number of users who have access to the build process means those users would lose their ability to make direct changes to that process.", + "RemediationProcedure": "Restrict access to the build environment to trusted and qualified users.", + "AuditProcedure": "Verify each build environment is accessible only to known and authorized users.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.6", + "Description": "Ensure users must authenticate to access the build environment", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Require users to login in to access the build environment - where the orchestrator, the pipeline executer, where the build workers are running, etc.", + "RationaleStatement": "Requiring users to authenticate and disabling anonymous access to the build environment allows organization to track every action on that environment, good or bad, to its actor. This will help recognizing attack and its attacker becuase the authentication is required.", + "ImpactStatement": "Anonymous users won't be able to access the build environment.", + "RemediationProcedure": "Require authentication to access the build environment and disable anonymous access.", + "AuditProcedure": "Ensure authentication is required to access the build environment.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.7", + "Description": "Ensure build secrets are limited to the minimal necessary scope", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Build tools providers offer a secure way to store secrets that should be used during the build process.\n These secrets will often be credentials used to access other tools, for example for pulling code or for uploading artifacts.\n Access to these secrets can be defined on various scopes, for example in github it could be on an organization level or a repository level and there is also control on whether these secrets are passed to forked pull request.\n To protect these critical assets it is important to choose the most restrictive scope necessary.", + "RationaleStatement": "Allowing over permissive access to these secrets may affect on their exposure.\n For example if a secret is defined in an organization level, and users can create new repositories, there is a scenario where a user can create a new repo and run a controlled build just to exfiltrate these secrets.", + "ImpactStatement": "Increased risk of exposure of build related secrets.", + "RemediationProcedure": "For each build tool, review the secrets defined and their permissions scope and change over permissive scopes to more restrictive ones based on the required access.", + "AuditProcedure": "For each build tool in use, review the secrets defined and the permission scopes they are assigned.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.8", + "Description": "Ensure the build infrastructure is automatically scanned for vulnerabilities", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Scan the build infrastructure and its dependencies for vulnerabilities. It is recommended that this be done automatically.", + "RationaleStatement": "Automatic scanning for vulnerabilities detects known vulnerabilities in the tooling used by the build infrastructure and its dependencies. These vulnerabilities can lead\n to a potentially massive breach if not handled as fast as possible, as attackers might also be\n aware of such vulnerabilities.", + "ImpactStatement": "", + "RemediationProcedure": "Set an automated vulnerability scanning for your build infrastructure.", + "AuditProcedure": "Verify that your build infrastructure is automatically scanned for vulnerabilities.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.9", + "Description": "Ensure default passwords are not used", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Do not use default passwords of build tools and components.", + "RationaleStatement": "Sometimes build tools and components are provided with default passwords for the first login. This password is intended to be used only on the first login and should be changed immediately after. Using the default password substantially increases the attack risk. It is especially important to ensure that default passwords are not used in build tools and components.", + "ImpactStatement": "", + "RemediationProcedure": "For each build tool, change the default password.", + "AuditProcedure": "For each build tool, ensure the password used is not the default one.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.10", + "Description": "Ensure webhooks of the build environment are secured", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use secured webhooks of the build environment.", + "RationaleStatement": "Webhooks are used for triggering an HTTP request based on an action made in the platform. Typically, build environment feature webhooks for a pipeline trigger based on source code event. Since webhooks are an HTTP POST request, they can be malformed if not secured over SSL. To prevent a potential hack and compromise of the webhook or to the environment or web server excepting the request, use only secured webhooks.", + "ImpactStatement": "", + "RemediationProcedure": "For each webhook in use, change it to secured (over HTTPS).", + "AuditProcedure": "For each webhook in use, ensure it is secured (HTTPS).", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.1.11", + "Description": "Ensure minimum number of administrators are set for the build environment", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure the build environment has a minimum number of administrators.", + "RationaleStatement": "Build environment administrators have the highest level of permissions, including the ability to add/remove users, create or delete pipelines, control build workers, change build trigger permissions and more. Due to the permissive access granted to a build environment administrator, it is highly recommended to keep the number of administrator accounts as minimal as possible.", + "ImpactStatement": "", + "RemediationProcedure": "Set the minimum number of administrators in the build environment.", + "AuditProcedure": "Verify that the build environment has only the minimum number of administrators.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.1", + "Description": "Ensure build workers are single-used", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use a clean instance of build worker for every pipeline run.", + "RationaleStatement": "Using a clean instance of build worker for every pipeline run eliminates the risks of data theft, data integrity breaches, and unavailability. It limits the pipeline's access to data stored on the file system from previous runs, and the cache is volatile. This prevents malicious changes from affecting other pipelines or the Continuous Integration/Continuous Delivery system itself.", + "ImpactStatement": "Data and cache will not be saved in different pipeline runs.", + "RemediationProcedure": "Create a clean build worker for every pipeline that is being run, or use build platform-hosted runners, as they typically offer a clean instance for every run.", + "AuditProcedure": "Ensure that every pipeline that is being run has its own clean, new runner.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.2", + "Description": "Ensure build worker environments and commands are passed and not pulled", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "A worker’s environment can be passed (for example, a pod in a Kubernetes cluster in which an environment variable is passed to it). It also can be pulled, like a virtual machine that is installing a package. Ensure that the environment and commands are passed to the workers and not pulled from it.", + "RationaleStatement": "Passing an environment means additional configuration happens in the build time phase and not in run time. It will also pass locally and not remotely. Passing a worker environment, instead of pulling it from an outer source, reduces the possibility for an attacker to gain access and potentially pull malicious code into it. By passing locally and not pulling from remote, there is also less chance of an attack based on the remote connection, such as a man-in-the-middle or malicious scripts that can run from remote. This therefore prevents possible infection of the build worker.", + "ImpactStatement": "", + "RemediationProcedure": "For each build worker, pass its environment and commands to it instead of pulling it.", + "AuditProcedure": "For each build worker, ensure its environment and commands are passed and not pulled.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.3", + "Description": "Ensure the duties of each build worker are segregated", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Separate responsibilities in the build workflow, such as testing, compiling, pushing artifacts, etc., to different build workers so that each worker will have a single duty.", + "RationaleStatement": "Separating duties and allocating them to many workers makes it easier to verify each step in the build process and ensure there is no corruption. It also limits the effect of an attack on a build worker, as such an attack would be less critical if the worker has less access and duties that are subject to harm.", + "ImpactStatement": "", + "RemediationProcedure": "For each build worker, limit its responsibility to one duty.", + "AuditProcedure": "For each build worker, ensure it has the least responsibility possible, preferably only one duty.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.4", + "Description": "Ensure build workers have minimal network connectivity", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure that build workers have minimal network connectivity.", + "RationaleStatement": "Restricting the network connectivity of build workers decreases the possibility that an attacker would be capable of entering the organization from the outside. If the build workers are connected to the public internet without any restriction, it is far simpler for attackers to compromise them. Limiting network connectivity between build workers also protects the organization in case an attacker was successful and subsequently attempts to spread the attack to other components of the environment.", + "ImpactStatement": "Developers will not have connectivity to every resource they might need from the outside. Workers will also only be able to exchange data through shareable storage.", + "RemediationProcedure": "Limit the network connectivity of build workers, environment, and any other components to the necessary minimum.", + "AuditProcedure": "Verify that build workers, environment, and any other components have only the required minimum of network connectivity.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.5", + "Description": "Ensure run-time security is enforced for build workers", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Add traces to build workers' operating systems and installed applications so that in run time, collected events can be analyzed to detect suspicious behavior patterns and malware.", + "RationaleStatement": "Build workers are exposed to data exfiltration attacks, code injection attacks, and more while running. It is important to secure them from such attacks by enforcing run-time security on the build worker itself. This will identify attempted attacks in real time and prevent them.", + "ImpactStatement": "", + "RemediationProcedure": "Deploy and enforce a run-time security solution on build workers.", + "AuditProcedure": "Verify that a run-time security solution is enforced on every active build worker.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.6", + "Description": "Ensure build workers are automatically scanned for vulnerabilities", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Scan build workers for vulnerabilities. It is recommended that this be done automatically.", + "RationaleStatement": "Automatic scanning for vulnerabilities detects known weaknesses in environmental sources in use, such as docker images or kernel versions. Such vulnerabilities can lead to a massive breach if these environments are not replaced as fast as possible, since attackers also know about these vulnerabilities and often try to take advantage of them. Setting automatic scanning which scans environmental sources ensures that if any new vulnerability is revealed, it can be replaced quickly and easily. This protects the worker from being exposed to attacks.", + "ImpactStatement": "", + "RemediationProcedure": "For each build worker, automatically scan its environmental sources, such as docker image, for vulnerabilities.", + "AuditProcedure": "For each build worker, ensure the environmental sources it uses are scanned for vulnerabilities.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.7", + "Description": "Ensure build workers' deployment configuration is stored in a version control platform", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Store the deployment configuration of build workers in a version control platform, such as Github.", + "RationaleStatement": "Build workers are a sensitive part of the build phase. They generally have access to the code repository, the Continuous Integration platform, the deployment platform, etc. This means that an attacker gaining access to a build worker may compromise other platforms in the organization and cause a major incident. One thing that can protect workers is to ensure that their deployment configuration is safe and well-configured. Storing the deployment configuration in version control enables more observability of these configurations because everything is catalogued in a single place. It adds another layer of security, as every change will be reviewed and noticed, and thus malicious changes will theoretically occur less. In the case of a mistake, bug, or security incident, it also offers an easier way to \"revert\" back to a safe version or add a \"hot fix\" quickly.", + "ImpactStatement": "Changes in deployment configuration may only be applied by declaration in the version control platform. This could potentially slow down the development process.", + "RemediationProcedure": "Document and store every deployment configuration of build workers in a version control platform.", + "AuditProcedure": "Verify that the deployment configuration of build workers is stored in a version control platform.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.2.8", + "Description": "Ensure resource consumption of build workers is monitored", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Monitor the resource consumption of build workers and set alerts for high consumption that can lead to resource exhaustion.", + "RationaleStatement": "Resource exhaustion is when machine resources or services are highly consumed until exhausted. Resource exhaustion may lead to DOS (Denial of Service). When such a situation happens to build workers, it slows down and even stops the build process, which harms the production of artifacts and the organization's ability to deliver software on schedule. To prevent that, it is recommended to monitor resources consumption in the build workers and set alerts to notify when they are highly consumed. That way resource exhaustion can be acknowledged and prevented at an early stage.", + "ImpactStatement": "", + "RemediationProcedure": "Set reources consumption monitoring for each build worker.", + "AuditProcedure": "Verify that there is monitoring of resources consumption for each build worker.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.1", + "Description": "Ensure all build steps are defined as code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use pipeline as code for build pipelines and their defined steps.", + "RationaleStatement": "Storing pipeline instructions as code in a version control system means automation of the build steps and less room for human error, which could potentially lead to a security breach. Additionally, It creates the ability to revert back to a previous pipeline configuration in order to pinpoint the affected change should a malicious incident occur.", + "ImpactStatement": "", + "RemediationProcedure": "Convert pipeline instructions into code-based syntax and upload them to the organization's version control platform.", + "AuditProcedure": "Verify that all build steps are defined as code and stored in a version control system.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.2", + "Description": "Ensure steps have clearly defined build stage input and output", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Define clear expected input and output for each build stage.", + "RationaleStatement": "In order to have more control over data flow in the build pipeline, clearly define the input and output of the pipeline steps. If anything malicious happens during the build stage, it will be recognized more easily and stand out as an anomaly.", + "ImpactStatement": "", + "RemediationProcedure": "For each build stage, clearly define what is expected for input and output.", + "AuditProcedure": "For each build stage, verify that the expected input and output are clearly defined.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.3", + "Description": "Ensure output is written to a separate, secured storage repository", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Write pipeline output artifacts to a secured storage repository.", + "RationaleStatement": "To maintain output artifacts securely and reduce the potential surface for attack, store such artifacts separately in secure storage. This separation enforces the Single Responsibility Principle by ensuring the orchestration platform will not be the same as the artifact storage, which reduces the potential harm of an attack. Using the same security considerations as the input (for example, the source code) will protect artifacts stored and will make it harder for a malicious actor to successfully execute an attack.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline that produces output artifacts, write them to a secured storage repository.", + "AuditProcedure": "For each pipeline that produces output artifacts, ensure that they're written to a secured storage repository.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.4", + "Description": "Ensure changes to pipeline files are tracked and reviewed", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Track and review changes to pipeline files.", + "RationaleStatement": "Pipeline files are sensitive files. They have the ability to access sensitive data and control the build process, thus it is just as important to review changes to pipeline files as it is to verify source code. Malicious actors can potentially add harmful code to these files, which may lead to sensitive data exposure and hijacking of the build environment or artifacts.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline file, track changes to it and review them.", + "AuditProcedure": "For each pipeline file, ensure changes to it are being tracked and reviewed.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.5", + "Description": "Ensure access to build process triggering is minimized", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Restrict access to pipeline triggers.", + "RationaleStatement": "Build pipelines are used for multiple reasons. Some are very sensitive, such as pipelines which deploy to production. In order to protect the environment from malicious acts or human mistakes, such as a developer deploying a bug to production, it is important to apply the Least Privilege principle to pipeline triggering. This principle requires restrictions placed on which users can run which pipeline. It allows for sensitive pipelines to only be run by administrators, who are generally the most trusted and skilled members of the organization.", + "ImpactStatement": "", + "RemediationProcedure": "For every pipeline in use, grant only the necessary users permission to trigger it.", + "AuditProcedure": "For every pipeline in use, verify only the necessary users have permission to trigger it.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.6", + "Description": "Ensure pipelines are automatically scanned for misconfigurations", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Scan the pipeline for misconfigurations. It is recommended that this be performed automatically.", + "RationaleStatement": "Automatic scans for misconfigurations detect human mistakes and misconfigured tasks. This protects the environment from backdoors caused by such mistakes, which create easier access for attackers. For example, a task that mistakenly configures credentials to persist on the disk makes it easier for an attacker to steal them. This type of incident can be prevented by auto-scanning.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline, set automated misconfiguration scanning.", + "AuditProcedure": "For each pipeline, verify that it is automatically scanned for misconfigurations.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.7", + "Description": "Ensure pipelines are automatically scanned for vulnerabilities", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Scan pipelines for vulnerabilities. It is recommended that this be implemented automatically.", + "RationaleStatement": "Automatic scanning for vulnerabilities detects known vulnerabilities in pipeline instructions and components, allowing faster patching in case one is found. These vulnerabilities can lead to a potentially massive breach if not handled as fast as possible, as attackers might also be aware of such vulnerabilities.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline, set automated vulnerability scanning.", + "AuditProcedure": "For each pipeline, verify that it is automatically scanned for vulnerabilities.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.3.8", + "Description": "Ensure scanners are in place to identify and prevent sensitive data in pipeline files", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.3", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "Detect and prevent sensitive data, such as confidential ID numbers, passwords, etc., in pipelines.", + "RationaleStatement": "Sensitive data in pipeline configuration, such as cloud provider credentials or repository credentials, create vulnerabilities with which malicious actors could steal such information if they gain access to a pipeline. In order to mitigate this, set scanners that will identify and prevent the existence of sensitive data in the pipeline.", + "ImpactStatement": "", + "RemediationProcedure": "For every pipeline that is in use, set scanners that will identify and prevent sensitive data within it.", + "AuditProcedure": "For every pipeline that is in use, verify that scanners are set to identify and prevent the existence of sensitive data within it.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.4.1", + "Description": "Ensure all artifacts on all releases are signed", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Sign all artifacts in all releases with user or organization keys.", + "RationaleStatement": "Signing artifacts is used to validate both their integrity and security. Organizations signal that artifacts may be trusted and they themselves produced them by ensuring that every artifact is properly signed. The presence of this signature also makes potentially malicious activity far more difficult.", + "ImpactStatement": "", + "RemediationProcedure": "For every artifact in every release, verify that all are properly signed.", + "AuditProcedure": "Ensure every artifact in every release is signed.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.4.2", + "Description": "Ensure all external dependencies used in the build process are locked", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "External dependencies may be public packages needed in the pipeline, or perhaps the public image being used for the build worker. Lock these external dependencies in every build pipeline.", + "RationaleStatement": "External dependencies are sources of code that aren't under organizational control. They might be intentionally or unintentionally infected with malicious code or have known vulnerabilities, which could result in sensitive data exposure, data harvesting, or the erosion of trust in an organization. Locking each external dependency to a specific, safe version gives more control and less chance for risk.", + "ImpactStatement": "", + "RemediationProcedure": "For all external dependencies being used in pipelines, verify they are locked.", + "AuditProcedure": "Ensure every external dependency being used in pipelines is locked.", + "AdditionalInformation": "", + "References": "https://argon.io/blog/pipeline-composition-analysis-how-your-ci-pipeline-presents-new-opportunities-for-attackers/" + } + ] + }, + { + "Id": "2.4.3", + "Description": "Ensure dependencies are validated before being used", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Validate every dependency of the pipeline before use.", + "RationaleStatement": "To ensure that a dependency used in a pipeline is trusted and has not been infected by malicious actor (for example, the codecov incident), validate dependencies before using them. This can be accomplished by comparing the checksum of the dependency to its checksum in a trusted source. If a difference arises, this is a sign that an unknown actor has interfered and may have added malevolent code. If this dependency is used, it will infect the environment, which could end in a massive breach and leave the organization exposed to data leaks, etc.", + "ImpactStatement": "", + "RemediationProcedure": "For every dependency used in every pipeline, validate each one.", + "AuditProcedure": "For every dependency used in every pipeline, ensure it has been validated.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.4.4", + "Description": "Ensure the build pipeline creates reproducible artifacts", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Verify that the build pipeline creates reproducible artifacts, meaning that an artifact of the build pipeline is the same in every run when given the same input.", + "RationaleStatement": "A reproducible build is a build that produces the same artifact when given the same input data. Ensuring that the build pipeline produces the same artifact when given the same input helps verify that no change has been made to the artifact. This action allows an organization to trust that its artifacts are built only from safe code that has been reviewed and tested and has not been tainted or changed abruptly.", + "ImpactStatement": "", + "RemediationProcedure": "Create build pipelines that produce the same artifact given the same input (for example, artifacts that do not rely on timestamps).", + "AuditProcedure": "Ensure that build pipelines create reproducible artifacts.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.4.5", + "Description": "Ensure pipeline steps produce a Software Bill of Materials (SBOM)", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "SBOM (Software Bill of Materials) is a file that specifies each component of software or a build process. Generate an SBOM after each run of a pipeline.", + "RationaleStatement": "Generating a Software Bill of Materials after each run of a pipeline will validate the integrity and security of that pipeline. Recording every step or component role in the pipeline ensures that no malicious acts have been committed during the pipeline's run.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline, configure it to produce a Software Bill of Materials on every run.", + "AuditProcedure": "For each pipeline, ensure it produces a Software Bill of Materials on every run.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "2.4.6", + "Description": "Ensure pipeline steps sign the Software Bill of Materials (SBOM) produced", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "2.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "SBOM (Software Bill of Materials) is a file that specifies each component of software or a build process. It should be generated after every pipeline run. After it is generated, it must then be signed.", + "RationaleStatement": "Software Bill of Materials (SBOM) is a file used to validate the integrity and security of a build pipeline. Signing it ensures that no one tampered with the file when it was delivered. Such interference can happen if someone tries to hide unusual activity. Validating the SBOM signature can detect this activity and prevent much greater incident.", + "ImpactStatement": "", + "RemediationProcedure": "For each pipeline, configure it to sign its produced Software Bill of Materials on every run.", + "AuditProcedure": "For each pipeline, ensure it signs the Software Bill of Materials it produces on every run.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.1", + "Description": "Ensure third-party artifacts and open-source libraries are verified", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure third-party artifacts and open-source libraries in use are trusted and verified.", + "RationaleStatement": "Verify third-party artifacts used in code are trusted and have not been infected by a malicious actor before use. This can be accomplished, for example, by comparing the checksum of the dependency to its checksum in a trusted source. If a difference arises, this may be a sign that someone interfered and added malicious code. If this dependency is used, it will infect the environment and could end in a massive breach, leaving the organization exposed to data leaks and more.", + "ImpactStatement": "", + "RemediationProcedure": "Verify every GitHub action (building block of a GitHub workflow) in use by performing the following: \n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the left sidebar, click **Actions**, then click **General**.\n 4. Under \"Policies\", check **Allow OWNER, and select non-OWNER, actions and reusable workflows**, and then **Allow actions created by GitHub**.\n 5. Click **Save**.\n \n\n Alternatively, perform the following for each repository where GitHub actions are used:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the left sidebar, click **Actions**, then click **General**.\n 4. Under \"Actions permissions\", check **Allow OWNER, and select non-OWNER, actions and reusable workflows**, and then **Allow actions created by GitHub**.\n 5. Click **Save**.", + "AuditProcedure": "For every GitHub action (building block of a GitHub workflow), ensure verification before use by performing the following: \n \n\n 1. In the top right corner of GitHub.com, click your profile photo, then click **Your organizations**.\n 2. Next to the organization, click **Settings**.\n 3. In the left sidebar, click **Actions**, then click **General**.\n 4. Under \"Policies\", ensure **Allow OWNER, and select non-OWNER, actions and reusable workflows**, and **Allow actions created by GitHub** are checked.\n \n\n Alternatively, perform the following for each repository where GitHub actions are used:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the left sidebar, click **Actions**, then click **General**.\n 4. Under \"Actions permissions\", ensure **Allow OWNER, and select non-OWNER, actions and reusable workflows** and **Allow actions created by GitHub** are checked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.2", + "Description": "Ensure Software Bill of Materials (SBOM) is required from all third-party suppliers", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "A Software Bill Of Materials (SBOM) is a file that specifies each component of software or a build process. Require an SBOM from every third-party provider.", + "RationaleStatement": "A Software Bill of Materials (SBOM) for every third-party artifact helps to ensure an artifact is safe to use and fully compliant. This file lists all important metadata, especially all the dependencies of an artifact, and allows for verification of each dependency. If one of the dependencies/artifacts are attacked or has a new vulnerability (for example, the \"SolarWinds\" or even \"log4j\" attacks), it is easier to detect what has been affected by this incident because dependencies in use are listed in the SBOM file.", + "ImpactStatement": "", + "RemediationProcedure": "For every third-party dependency in use, require a Software Bill of Materials from its supplier.", + "AuditProcedure": "For every third-party dependency in use, ensure it has a Software Bill of Materials.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.3", + "Description": "Ensure signed metadata of the build process is required and verified", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Require and verify signed metadata of the build process for all dependencies in use.", + "RationaleStatement": "The metadata of a build process lists every action that took place during an artifact build. It is used to ensure that an artifact has not been compromised during the build, that no malicious code was injected into it, and that no nefarious dependencies were added during the build phase. This creates trust between user and vendor that the software supplied is exactly the software that was promised. Signing this metadata adds a checksum to ensure there have been no revisions since its creation, as this checksum changes when the metadata is altered. Verification of proper metadata signature with Certificate Authority confirms that the signature was produced by a trusted entity.", + "ImpactStatement": "", + "RemediationProcedure": "For each artifact in use, require and verify signed metadata of the build process.", + "AuditProcedure": "For each artifact used, ensure it was supplied with verified and signed metadata of its build process. The signature should be the organizational signature and should be verifiable by common Certificate Authority servers.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.4", + "Description": "Ensure dependencies are monitored between open-source components", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Monitor, or ask software suppliers to monitor, dependencies between open-source components in use.", + "RationaleStatement": "Monitoring dependencies between open-source components helps to detect if software has fallen victim to attack on a common open-source component. Swift detection can aid in quick application of a fix. It also helps find potential compliance problems with components usage. Some dependencies might not be compatible with the organization's policies, and other dependencies might have a license that is not compatible with how the organization uses this specific dependency. If dependencies are monitored, such situations can be detected and mitigated sooner, potentially deterring malicious attacks.", + "ImpactStatement": "", + "RemediationProcedure": "For each open-source component, monitor its dependencies.", + "AuditProcedure": "For each open-source component, ensure its dependencies are monitored.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.5", + "Description": "Ensure trusted package managers and repositories are defined and prioritized", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Prioritize trusted package registries over others when pulling a package.", + "RationaleStatement": "When pulling a package by name, the package manager might look for it in several package registries, some of which may be untrusted or badly configured. If the package is pulled from such a registry, there is a higher likelihood that it could prove malicious. In order to avoid this, configure packages to be pulled from trusted package registries.", + "ImpactStatement": "", + "RemediationProcedure": "For each package to be downloaded, configure it to be downloaded from a trusted source.", + "AuditProcedure": "For each package registry in use, ensure it is trusted.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.6", + "Description": "Ensure a signed Software Bill of Materials (SBOM) of the code is supplied", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "A Software Bill of Materials (SBOM) is a file that specifies each component of software or a build process. When using a dependency, demand its SBOM and ensure it is signed for validation purposes.", + "RationaleStatement": "A Software Bill of Materials (SBOM) creates trust between its provider and its users by ensuring that the software supplied is the software described, without any potential interference in between. Signing an SBOM creates a checksum for it, which will change if the SBOM's content was changed. With that checksum, a software user can be certain nothing had happened to it during the supply chain, engendering trust in the software. When there is no such trust in the software, the risk surface is increased because one cannot know if the software is potentially vulnerable. Demanding a signed SBOM and validating it decreases that risk.", + "ImpactStatement": "", + "RemediationProcedure": "For every artifact supplied, require and verify a signed Software Bill of Materials from its supplier.", + "AuditProcedure": "For every artifact supplied, ensure it has a validated, signed Software Bill of Materials.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.7", + "Description": "Ensure dependencies are pinned to a specific, verified version", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Pin dependencies to a specific version. Avoid using the \"latest\" tag or broad version.", + "RationaleStatement": "When using a wildcard version of a package, or the \"latest\" tag, the risk of encountering a new, potentially malicious package increases. The \"latest\" tag pulls the last package pushed to the registry. This means that if an attacker pushes a new, malicious package successfully to the registry, the next user who pulls the \"latest\" will pull it and risk attack. This same rule applies to a wildcard version - assuming one is using version v1.*, it will install the latest version of the major version 1, meaning that if an attacker can push a malicious package with that same version, those using it will be subject to possible attack. By using a secure, verified version, use is restricted to this version only and no other may be pulled, decreasing the risk for any malicious package.", + "ImpactStatement": "", + "RemediationProcedure": "For every dependency in use, pin to a specific version.", + "AuditProcedure": "For every dependency in use, ensure it is pinned to a specific version.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.1.8", + "Description": "Ensure all packages used are more than 60 days old", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Use packages that are more than 60 days old.", + "RationaleStatement": "Third-party packages are a major risk since an organization cannot control their source code, and there is always the possibility these packages could be malicious. It is therefore good practice to remain cautious with any third-party or open-source package, especially new ones, until they can be verified that they are safe to use. Avoiding a new package allows the organization to fully examine it, its maintainer, and its behavior, and gives enough time to determine whether or not to use it.", + "ImpactStatement": "Developers may not use packages that are less than 60 days old.", + "RemediationProcedure": "If a package used is less than 60 days old, stop using it and find another solution.", + "AuditProcedure": "For every package used, ensure it is more than 60 days old.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "", + "Description": "Validate Packages", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.2", + "Profile": "", + "AssessmentStatus": "", + "Description": "This section consists of security recommendations for managing package validations and checks. Third-party packages and dependencies might put the organization in danger, not only by being vulnerable to attacks, but also by being improperly used and harming license conditions. To protect the software supply chain from these dangers, it is important to validate packages and understand how and if to use them. This section's recommendations cover this topic.", + "RationaleStatement": "", + "ImpactStatement": "", + "RemediationProcedure": "", + "AuditProcedure": "", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure an organization-wide dependency usage policy is enforced", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Enforce a policy for dependency usage across the organization. For example, disallow the use of packages less than 60 days old.", + "RationaleStatement": "Enforcing a policy for dependency usage in an organization helps to manage dependencies across the organization and ensure that all usage is compliant with security policy. If, for example, the policy limits the package managers that can be used, enforcing it will make sure that every dependency is installed only from these package managers, and limit the risk of installing from any untrusted source.", + "ImpactStatement": "", + "RemediationProcedure": "Enforce policies for dependency usage across the organization.", + "AuditProcedure": "Verify that a policy for dependency usage is enforced across the organization.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.2.2", + "Description": "Ensure packages are automatically scanned for known vulnerabilities", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Automatically scan every package for vulnerabilities.", + "RationaleStatement": "Automatic scanning for vulnerabilities detects known vulnerabilities in packages and dependencies in use, allowing faster patching when one is found. Such vulnerabilities can lead to a massive breach if not handled as fast as possible, as attackers will also know about those vulnerabilities and swiftly try to take advantage of them. Scanning packages regularly for vulnerabilities can also verify usage compliance with the organization's security policy.", + "ImpactStatement": "", + "RemediationProcedure": "Set automatic scanning of packages for vulnerabilities.", + "AuditProcedure": "Ensure automatic scanning of packages for vulnerabilities is enabled.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.2.3", + "Description": "Ensure packages are automatically scanned for license implications", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "A software license is a document that provides legal conditions and guidelines for the use and distribution of software, usually defined by the author. It is recommended to scan for any legal implications automatically.", + "RationaleStatement": "When using packages with software licenses, especially commercial ones which tend to be the strictest, it is important to verify that the use of the package meets the conditions of the license. If the use of the package violates the licensing agreement, it exposes the organization to possible lawsuits. Scanning used packages for such license implications leads to faster detection and quicker fixes of such violations, and also reduces the risk for a lawsuit.", + "ImpactStatement": "", + "RemediationProcedure": "Set automatic package scanning for license implications.", + "AuditProcedure": "Ensure license implication rules are configured and are scanned automatically.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "3.2.4", + "Description": "Ensure packages are automatically scanned for ownership change", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "3.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Scan every package automatically for ownership change.", + "RationaleStatement": "A change in package ownership is not a regular action. In some cases it can lead to a massive problem (for example, the \"event-stream\" incident). Open-source contributors are not always trusted, since by its very nature everyone can contribute. This means malicious actors can become contributors as well. Package maintainers might transfer their ownership to someone they do not know if maintaining the package is too much for them, in some cases without the other user's knowledge. This has led to known security breaches in the past. It is best to be aware of such activity as soon as it happens and to carefully examine the situation before continuing using the package in order to determine its safety.", + "ImpactStatement": "", + "RemediationProcedure": "Set automatic scanning of packages for ownership change.", + "AuditProcedure": "Ensure automatic scanning of packages for ownership change is set.", + "AdditionalInformation": "", + "References": "https://blog.npmjs.org/post/182828408610/the-security-risks-of-changing-package-owners.html:https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident" + } + ] + }, + { + "Id": "4.1.1", + "Description": "Ensure all artifacts are signed by the build pipeline itself", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Configure the build pipeline to sign every artifact it produces and verify that each artifact has the appropriate signature.", + "RationaleStatement": "A cryptographic signature can be used to verify artifact authenticity. The signature created with a certain key is unique and not reversible, thus making it unique to the author. This means that an attacker tampering with a signed artifact will be noticed immediately using a simple verification step because the signature will change. Signing artifacts by the build pipeline that produces them ensures the integrity of those artifacts.", + "ImpactStatement": "", + "RemediationProcedure": "Sign every artifact produced with the build pipeline that created it. Configure the build pipeline to sign each artifact.\n \n\n Steps from GitHub Documentation:\n \n\n You can follow the steps below to sign artifacts in GitHub actions. The trick involves loading in your private key into GitHub Actions using the gpg command-line commands.\n \n\n Export your gpg private key from the system that you have created it.\n Find your key-id (using gpg --list-secret-keys --keyid-format=long)\n Export the gpg secret key to an ASCII file using gpg --export-secret-keys -a > secret.txt\n Edit secret.txt using a plain text editor, and replace all newlines with a literal \"\\n\" until everything is on a single line\n Set up GitHub Actions secrets\n Create a secret called OSSRH_GPG_SECRET_KEY using the text from your edited secret.txt file (the whole text should be in a single line)\n Create a secret called OSSRH_GPG_SECRET_KEY_PASSWORD containing the password for your gpg secret key\n Create a GitHub Actions step to install the gpg secret key\n Add an action similar to:\n ```\n - id: install-secret-key\n name: Install gpg secret key\n run: |\n cat <(echo -e \"${{ secrets.OSSRH_GPG_SECRET_KEY }}\") | gpg --batch --import\n gpg --list-secret-keys --keyid-format LONG\n ```\n Verify that the secret key is shown in the GitHub Actions logs\n You can remove the output from list secret keys if you are confident that this action will work, but it is better to leave it in there\n Bring it all together, and create a GitHub Actions step to publish\n Add an action similar to:\n ```\n - id: publish-to-central\n name: Publish to Central Repository\n env:\n MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}\n MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}\n run: |\n mvn \\\n --no-transfer-progress \\\n --batch-mode \\\n -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} \\\n clean deploy\n ```\n After a couple of hours, verify that the artifact got published to The Central Repository", + "AuditProcedure": "Verify that the build pipeline signs every new artifact it produces and all artifacts are signed.\n \n\n There are many different signing tools or options each have there own method or commands to verify that the code or package created is signed.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/code-security/supply-chain-security/end-to-end-supply-chain/securing-builds:https://gist.github.com/sualeh/ae78dc16123899d7942bc38baba5203c" + } + ] + }, + { + "Id": "4.1.2", + "Description": "Ensure artifacts are encrypted before distribution", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Encrypt artifacts before they are distributed and ensure only trusted platforms have decryption capabilities.", + "RationaleStatement": "Build artifacts might contain sensitive data such as production configurations. In order to protect them and decrease the risk for breach, it is recommended to encrypt them before delivery. Encryption makes data unreadable, so even if attackers gain access to these artifacts, they won't be able to harvest sensitive data from them without the decryption key.", + "ImpactStatement": "", + "RemediationProcedure": "Encrypt every artifact before distribution.", + "AuditProcedure": "Ensure every artifact is encrypted before it is delivered.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.1.3", + "Description": "Ensure only authorized platforms have decryption capabilities of artifacts", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Grant decryption capabilities of artifacts only to trusted and authorized platforms.", + "RationaleStatement": "Build artifacts might contain sensitive data such as production configuration. To protect them and decrease the risk of a breach, it is recommended to encrypt them before delivery. This will make them unreadable for every unauthorized user who doesn't have the decryption key. By implementing this, the decryption capabilities become overly sensitive in order to prevent a data leak or theft. Ensuring that only trusted and authorized platforms can decrypt the organization's packages decreases the possibility for an attacker to gain access to the critical data in artifacts.", + "ImpactStatement": "", + "RemediationProcedure": "Grant decryption capabilities of the organization's artifacts only for trusted and authorized platforms.", + "AuditProcedure": "Ensure only trusted and authorized platforms have decryption capabilities of the organization's artifacts.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "", + "Description": "Access to Artifacts", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "", + "AssessmentStatus": "", + "Description": "This section consists of security recommendations for access management of artifacts. \n \n\n Artifacts are often stored in registries, some external and some internal. Those registries have user entities that control access and permissions. Artifacts are considered sensitive, because they are being delivered to the costumer, and are prune to many attacks: data theft, dependency confusion, malicious packages and more. That's why their access management should be restrictive and careful.", + "RationaleStatement": "", + "ImpactStatement": "", + "RemediationProcedure": "", + "AuditProcedure": "", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.2.1", + "Description": "Ensure the authority to certify artifacts is limited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Software certification is used to verify the safety of certain software usage and to establish trust between the supplier and the consumer. Any artifact can be certified. Limit the authority to certify different artifacts.", + "RationaleStatement": "Artifact certification is a powerful tool in establishing trust. Clients use a software certificate to verify that the artifact is safe to use according to their security policies. Because of this, certifying artifacts is considered sensitive. If an artifact is for debugging or internal use, or if it were compromised, the organization would not want certification. An attacker gaining access to both certificate authority and the artifact registry might also be able to certify its own artifact and cause a major breach. To prevent these issues, limit which artifacts can be certified by which platform so there will be minimal access to certification.", + "ImpactStatement": "", + "RemediationProcedure": "Limit which artifact can be certified by which authority.", + "AuditProcedure": "Ensure only certain artifacts can be certified by certain parties.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.2.2", + "Description": "Ensure number of permitted users who may upload new artifacts is minimized", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Minimize ability to upload artifacts to the lowest number of trusted users possible.", + "RationaleStatement": "Artifacts might contain sensitive data. Even the simplest mistake can also lead to trust issues with customers and harm the integrity of the product. To decrease these risks, allow only trusted and qualified users to upload new artifacts. Those users are less likely to make mistakes. Having the lowest number of such users possible will also decrease the risk of hacked user accounts, which could lead to a massive breach or artifact compromising.", + "ImpactStatement": "", + "RemediationProcedure": "Allow only trusted and qualified users to upload new artifacts and limit them in number.", + "AuditProcedure": "Ensure only trusted and qualified users can upload new artifacts, and that their number is the lowest possible.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.2.3", + "Description": "Ensure user access to the package registry utilizes Multi-Factor Authentication (MFA)", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Enforce Multi-Factor Authentication (MFA) for user access to the package registry.", + "RationaleStatement": "By default, every user authenticates to the system by password only. If a user's password is compromised, the user account and all its related packages are in danger of data theft and malicious builds. It is therefore recommended that each user enables Multi-Factor Authentication. This additional step guarantees that the account stays secure even if the user's password is compromised, as it adds another layer of authentication.", + "ImpactStatement": "", + "RemediationProcedure": "For each package registry in use, enforce Multi-Factor Authentication as the only way to authenticate.", + "AuditProcedure": "For each package registry in use, verify that Multi-Factor Authentication is enforced and is the only way to authenticate.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.2.4", + "Description": "Ensure user management of the package registry is not local", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Manage users and their access to the package registry with an external authentication server and not with the package registry itself.", + "RationaleStatement": "Some package registries offer a tool for user management, aside from the main Lightweight Directory Access Protocol (LDAP) or Active Directory (AD) server of the organization. That tool usually offers simple authentication and role-based permissions, which might not be granular enough. Having multiple user management tools in the organization could result in confusion and privilege escalation, as there will be more to manage. To avoid a situation where users escalate their privileges because someone missed them, manage user access to the package registry via the main authentication server and not locally on the package registry.", + "ImpactStatement": "", + "RemediationProcedure": "For each package registry, use the main authentication server of the organization for user management and do not manage locally.", + "AuditProcedure": "For each package registry, verify that its user access is not managed locally, but instead with the main authentication server of the organization.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.2.5", + "Description": "Ensure anonymous access to artifacts is revoked", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "For GitHub Private or Internal repositories anonymous access is not available. Verify that all repos that require access controls are Private or Internal.", + "RationaleStatement": "Disable the option to view artifacts as an anonymous user in order to protect private artifacts from being exposed.", + "ImpactStatement": "Only logged and authorized users will be able to access artifacts.", + "RemediationProcedure": "Changing a repository's visibility\n \n\n 1. On your GitHub Enterprise Server instance, navigate to the main page of the repository.\n 1. Under your repository name, click Settings\n 1. Under \"Danger Zone\", to the right of to \"Change repository visibility\", click Change visibility.\n 1. Select a visibility.\n \n\n 1. Choose \n - Mark private\n - Make Internal\n \n\n 6. To verify that you're changing the correct repository's visibility, type the name of the repository you want to change the visibility of.", + "AuditProcedure": "To Audit the existing settings:\n \n\n 1. On your GitHub Enterprise Server instance, navigate to the main page of the repository.\n 1. Under your repository name, click Settings\n 3. Under \"Danger Zone\", to the right of to \"Change repository visibility\", click Change visibility.\n \n\n Review the current selection.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/enterprise-server@3.3/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/setting-repository-visibility" + } + ] + }, + { + "Id": "4.2.6", + "Description": "Ensure minimum number of administrators are set for the package registry", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure the package registry has a minimum number of administrators.", + "RationaleStatement": "Package registry admins have the ability to add/remove users, repositories, packages. Due to the permissive access granted to an admin, it is highly recommended to keep the number of administrator accounts as minimal as possible.", + "ImpactStatement": "Administrator privileges are required to provide and maintain a secure and stable platform but allowing extraneous administrator accounts can create a vulnerability.", + "RemediationProcedure": "Set the minimum number of administrators in your package registry.\n \n\n To accomplish this:\n \n\n For each repository that you administer on GitHub, you can see an overview of every team or person with access to the repository. From the overview, choose Manage access and provide access to the appropriate people or teams.", + "AuditProcedure": "Verify that your package registry has only the minimum number of administrators.\n \n\n For each repository that you administer on GitHub, you can see an overview of every team or person with access to the repository. From the overview, you can also invite new teams or people, change each team or person's role for the repository, or remove access to the repository.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-teams-and-people-with-access-to-your-repository" + } + ] + }, + { + "Id": "4.3.1", + "Description": "Ensure all signed artifacts are validated upon uploading the package registry", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Validate artifact signatures before uploading to the package registry.", + "RationaleStatement": "Cryptographic signature is a tool to verify artifact authenticity. Every artifact is supposed to be signed by its creator in order to confirm that it was not compromised before reaching the client. Validating an artifact signature before delivering it is another level of protection which ensures the signature has not been changed, meaning no one tried or succeeded in tampering with the artifact. This creates trust between the supplier and the client.", + "ImpactStatement": "", + "RemediationProcedure": "Validate every artifact with its signature before uploading it to the package registry. It is recommended to do so automatically.", + "AuditProcedure": "Ensure every artifact in the package registry has been validated with its signature.\n \n\n 1. On GitHub, navigate to a pull request\n 2. On the pull request, click <> Commits and view the detailed information regarding the signature.", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification:https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits" + } + ] + }, + { + "Id": "4.3.2", + "Description": "Ensure all versions of an existing artifact have their signatures validated", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Validate the signature of all versions of an existing artifact.", + "RationaleStatement": "In order to be certain a version of an existing and trusted artifact is not malicious or delivered by someone looking to interfere with the supply chain, it is a good practice to validate the signatures of each version. Doing so decreases the risk of using a compromised artifact, which might lead to a breach.", + "ImpactStatement": "", + "RemediationProcedure": "For each artifact, sign and validate each version before uploading or using the artifact.", + "AuditProcedure": "For each artifact, ensure that all of its versions are signed and validated before it is uploaded or used.\n \n\n Ensure every artifact in the package registry has been validated with its signature.\n \n\n On GitHub, navigate to a pull request\n On the pull request, click <> Commits and view the detailed information regarding the signature.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.3.3", + "Description": "Ensure changes in package registry configuration are audited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Audit changes of the package registry configuration.", + "RationaleStatement": "The package registry is a crucial component in the software supply chain. It stores artifacts with potentially sensitive data that will eventually be deployed and used in production. Every change made to the package registry configuration must be examined carefully to ensure no exposure of the registry's sensitive data. This examination also ensures no malicious actors have performed modifications to a stored artifact. Auditing the configuration and its changes helps in decreasing such risks.", + "ImpactStatement": "", + "RemediationProcedure": "Audit the changes to the package registry configuration.", + "AuditProcedure": "Verify that all changes to the packages registry configuration are audited.\n \n\n Search the audit log with\n \n\n repo category actions", + "AdditionalInformation": "", + "References": "https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization" + } + ] + }, + { + "Id": "4.3.4", + "Description": "Ensure webhooks of the repository are secured", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.3", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Use secured webhooks to reduce the possibility of malicious payloads.", + "RationaleStatement": "Webhooks are used for triggering an HTTP request based on an action made in the platform. Typically, package registries feature webhooks when a package receives an update. Since webhooks are an HTTP POST request, they can be malformed if not secured over SSL. To prevent a potential hack and compromise of the webhook or to the registry or web server excepting the request, use only secured webhooks.", + "ImpactStatement": "Reduces the payloads that the web hook can listen for and recieve.", + "RemediationProcedure": "For each webhook in use, change it to secured (over HTTPS).", + "AuditProcedure": "", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "4.4.1", + "Description": "Ensure artifacts contain information about their origin", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "4.4", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "When delivering artifacts, ensure they have information about their origin. This may be done by providing a Software Bill of Manufacture (SBOM) or some metadata files.", + "RationaleStatement": "Information about artifact origin can be used for verification purposes. Having this kind of information allows the user to decide if the organization supplying the artifact is trusted. In a case of potential vulnerability or version update, this can be used to verify that the organization issuing it is the actual origin and not someone else. If users need to report problems with the artifact, they will have an address to contact as well.", + "ImpactStatement": "", + "RemediationProcedure": "For each artifact supplied, supply information about its origin. For each artifact in use, ask for information about its origin.", + "AuditProcedure": "For each artifact, ensure it has information about its origin.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.1", + "Description": "Ensure deployment configuration files are separated from source code", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Deployment configurations are often stored in a version control system. Separate deployment configuration files from source code repositories.", + "RationaleStatement": "Deployment configuration manifests are often stored in version control systems. Storing them in dedicated repositories, separately from source code repositories, has several benefits. First, it adds order to both maintenance and version control history. This makes it easier to track code or manifest changes, as well as spot any malicious code or misconfigurations. Second, it helps achieve the Least Privilege principle. Because access can be configured differently for each repository, fewer users will have access to this configuration, which is typically sensitive.", + "ImpactStatement": "", + "RemediationProcedure": "Store each deployment configuration file in a dedicated repository separately from source code.", + "AuditProcedure": "Ensure each deployment configuration file is stored separately from source code.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.2", + "Description": "Ensure changes in deployment configuration are audited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Audit and track changes made in deployment configuration.", + "RationaleStatement": "Deployment configuration is sensitive in nature. The tiniest mistake can lead to downtime or bugs in production, which consequently may have a direct effect on both product integrity and customer trust. Misconfigurations might also be used by malicious actors to attack the production platform. Because of this, every change in the configuration needs a review and possible \"revert\" in case of a mistake or malicious change. Auditing every change and tracking them helps detect and fix such incidents more quickly.", + "ImpactStatement": "", + "RemediationProcedure": "For each deployment configuration, track and audit changes made to it.", + "AuditProcedure": "For each deployment configuration, ensure changes made to it are audited and tracked.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.3", + "Description": "Ensure scanners are in place to identify and prevent sensitive data in deployment configuration", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent sensitive data – such as confidential ID numbers, passwords, etc. – in deployment configurations.", + "RationaleStatement": "Sensitive data in deployment configurations might create a major incident if an attacker gains access to it, as this can cause data loss and theft. It is important to keep sensitive data safe and to not expose it in the configuration. In order to prevent a possible exposure, set scanners that will identify and prevent such data in deployment configurations.", + "ImpactStatement": "", + "RemediationProcedure": "For each deployment configuration file, set scanners to identify and prevent sensitive data within it.", + "AuditProcedure": "For each deployment configuration file, verify that scanners are set to identify and prevent the existence of sensitive data within it.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.4", + "Description": "Limit access to deployment configurations", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Restrict access to the deployment configuration to trusted and qualified users only.", + "RationaleStatement": "Deployment configurations are sensitive in nature. The tiniest mistake can lead to downtime or bugs in production, which can have a direct effect on the product's integrity and customer trust. Misconfigurations might also be used by malicious actors to attack the production platform. To avoid such harm as much as possible, ensure only trusted and qualified users have access to such configurations. This will also reduce the number of accounts that might affect the environment in case of an attack.", + "ImpactStatement": "Reducing the number of users who have access to the deployment configuration means those users would lose their ability to make direct changes to that configuration.", + "RemediationProcedure": "Restrict access to the deployment configuration to trusted and qualified users.", + "AuditProcedure": "Verify each deployment configuration is accessible only to known and authorized users.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.5", + "Description": "Scan Infrastructure as Code (IaC)", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Detect and prevent misconfigurations or insecure instructions in Infrastructure as Code (IaC) files, such as Terraform files.", + "RationaleStatement": "Infrastructure as Code (IaC) files are used for production environment and application deployment. These are sensitive parts of the software supply chain because they are always in touch with customers, and thus might affect their opinion of or trust in the product. Attackers often target these environments. Detecting and fixing misconfigurations and/or insecure instructions in IaC files decreases the risk for data leak or data theft. It is important to secure IaC instructions in order to prevent further problems of deployment, exposed assets, or improper configurations, which might ultimately lead to easier ways to attack and steal organization data.", + "ImpactStatement": "", + "RemediationProcedure": "For every Infrastructure as Code (IaC) instructions file, set scanners to identify and prevent misconfigurations and insecure instructions.", + "AuditProcedure": "For every Infrastructure as Code (IaC) instructions file, verify that scanners are set to identify and prevent misconfigurations and insecure instructions.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.6", + "Description": "Ensure deployment configuration manifests are verified", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Verify the deployment configuration manifests.", + "RationaleStatement": "To ensure that the configuration manifests used are trusted and have not been infected by malicious actors before arriving at the platform, it is important to verify the manifests. This may be done by comparing the checksum of the manifest file to its checksum in a trusted source. If a difference arises, this is a sign that an unknown actor has interfered and may have added malicious instructions. If this manifest is used, it might harm the environment and application deployment, which could end in a massive breach and leave the organization exposed to data leaks, etc.", + "ImpactStatement": "", + "RemediationProcedure": "Verify each deployment configuration manifest in use.", + "AuditProcedure": "For each deployment configuration manifest in use, ensure it has been verified.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.1.7", + "Description": "Ensure deployment configuration manifests are pinned to a specific, verified version", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.1", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Deployment configuration is often stored in a version control system and is pulled from there. Pin the configuration used to a specific, verified version or commit Secure Hash Algorithm (SHA). Avoid referring configuration without its version tag specified.", + "RationaleStatement": "Deployment configuration manifests are often stored in version control systems and pulled from there either by automation platforms, for example Ansible, or GitOps platforms, such as ArgoCD. When a manifest is pulled from a version control system without tag or commit Secure Hash Algorithm (SHA) specified, it is pulled from the HEAD revision, which is equal to the 'latest' tag, and pulls the last change made. This increases the risk of encountering a new, potentially malicious configuration. If an attacker pushes malicious configuration to the version control system, the next user who pulls the HEAD revision will pull it and risk attack. To avoid that risk, use a version tag of verified version or a commit SHA of a trusted commit, which will ensure this is the only version pulled.", + "ImpactStatement": "Changes in deployment configuration will not be pulled unless their version tag or commit Secure Hash Algorithm (SHA) is specified. This might slow down the deployment process.", + "RemediationProcedure": "For every deployment configuration manifest in use, pin to a specific version or commit Secure Hash Algorithm (SHA).", + "AuditProcedure": "For every deployment configuration manifest in use, ensure it is pinned to a specific version or commit Secure Hash Algorithm (SHA).", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.2.1", + "Description": "Ensure deployments are automated", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Automate deployments of production environment and application.", + "RationaleStatement": "Automating the deployments of both production environment and applications reduces the risk for human mistakes — such as a wrong configuration or exposure of sensitive data — because it requires less human interaction or intervention. It also eases redeployment of the environment. It is best to automate with Infrastructure as Code (IaC) because it offers more control over changes made to the environment creation configuration and stores to a version control platform.", + "ImpactStatement": "", + "RemediationProcedure": "Automate each deployment process of the production environment and application.", + "AuditProcedure": "For each deployment process, ensure it is automated.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.2.2", + "Description": "Ensure the deployment environment is reproducible", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Verify that the deployment environment – the orchestrator and the production environment where the application is deployed – is reproducible. This means that the environment stays the same in each deployment if the configuration has not changed.", + "RationaleStatement": "A reproducible build is a build that produces the same artifact when given the same input data, and in this case the same environment. Ensuring that the same environment is produced when given the same input helps verify that no change has been made to it. This action allows an organization to trust that its deployment environment is built only from safe code and configuration that has been reviewed and tested and has not been tainted or changed abruptly.", + "ImpactStatement": "", + "RemediationProcedure": "Adjust the process that deploys the deployment/production environment to build the same environment each time when the configuration has not changed.", + "AuditProcedure": "Verify that the deployment/production environment is reproducible.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.2.3", + "Description": "Ensure access to production environment is limited", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Restrict access to the production environment to a few trusted and qualified users only.", + "RationaleStatement": "The production environment is an extremely sensitive one. It directly affects the customer experience and trust in a product, which has serious effects on the organization itself. Because of this sensitive nature, it is important to restrict access to the production environment to only a few trusted and qualified users. This will reduce the risk of mistakes such as exposure of secrets or misconfiguration. This restriction also reduces the number of accounts that are vulnerable to hijacking in order to potentially harm the production environment.", + "ImpactStatement": "Reducing the number of users who have access to the production environment means those users would lose their ability to make direct changes to that environment.", + "RemediationProcedure": "Restrict access to the production environment to trusted and qualified users.", + "AuditProcedure": "Verify that the production environment is accessible only to trusted and qualified users.", + "AdditionalInformation": "", + "References": "" + } + ] + }, + { + "Id": "5.2.4", + "Description": "Ensure default passwords are not used", + "Checks": [ + "" + ], + "Attributes": [ + { + "Section": "5.2", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Do not use default passwords of deployment tools and components.", + "RationaleStatement": "Many deployment tools and components are provided with default passwords for the first login. This password is intended to be used only on the first login and should be changed immediately after. Using the default password substantially increases the attack risk. It is very important to ensure that default passwords are not used in deployment tools and components.", + "ImpactStatement": "", + "RemediationProcedure": "For each deployment tool, change the password.", + "AuditProcedure": "For each deployment tool, ensure the password is not the default one.", + "AdditionalInformation": "", + "References": "" + } + ] + } + ] } diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index f2cc8d12dd..1990c7f90a 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -34,6 +34,7 @@ Available Cloud Providers: azure Azure Provider gcp GCP Provider kubernetes Kubernetes Provider + github GitHub Provider m365 Microsoft 365 Provider nhn NHN Provider (Unofficial) diff --git a/prowler/lib/outputs/compliance/cis/cis_github.py b/prowler/lib/outputs/compliance/cis/cis_github.py new file mode 100644 index 0000000000..c06a766a05 --- /dev/null +++ b/prowler/lib/outputs/compliance/cis/cis_github.py @@ -0,0 +1,101 @@ +from datetime import datetime + +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.cis.models import GithubCISModel +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.finding import Finding + + +class GithubCIS(ComplianceOutput): + """ + This class represents the GitHub CIS compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into GitHub CIS compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into GitHub CIS compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = GithubCISModel( + Provider=finding.provider, + Description=compliance.Description, + Account_Id=finding.account_uid, + Account_Name=finding.account_name, + AssessmentDate=str(finding.timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_Profile=attribute.Profile, + Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus, + Requirements_Attributes_Description=attribute.Description, + Requirements_Attributes_RationaleStatement=attribute.RationaleStatement, + Requirements_Attributes_ImpactStatement=attribute.ImpactStatement, + Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure, + Requirements_Attributes_AuditProcedure=attribute.AuditProcedure, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_References=attribute.References, + Requirements_Attributes_DefaultValue=attribute.DefaultValue, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = GithubCISModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + Account_Id="", + Account_Name="", + AssessmentDate=str(datetime.now()), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_Profile=attribute.Profile, + Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus, + Requirements_Attributes_Description=attribute.Description, + Requirements_Attributes_RationaleStatement=attribute.RationaleStatement, + Requirements_Attributes_ImpactStatement=attribute.ImpactStatement, + Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure, + Requirements_Attributes_AuditProcedure=attribute.AuditProcedure, + Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation, + Requirements_Attributes_References=attribute.References, + Requirements_Attributes_DefaultValue=attribute.DefaultValue, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/cis/models.py b/prowler/lib/outputs/compliance/cis/models.py index 201925f19d..8ddbc3f1de 100644 --- a/prowler/lib/outputs/compliance/cis/models.py +++ b/prowler/lib/outputs/compliance/cis/models.py @@ -163,6 +163,37 @@ class KubernetesCISModel(BaseModel): Muted: bool +class GithubCISModel(BaseModel): + """ + GithubCISModel generates a finding's output in Github CIS Compliance format. + """ + + Provider: str + Description: str + Account_Name: str + Account_Id: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Attributes_Section: str + Requirements_Attributes_Profile: str + Requirements_Attributes_AssessmentStatus: str + Requirements_Attributes_Description: str + Requirements_Attributes_RationaleStatement: str + Requirements_Attributes_ImpactStatement: str + Requirements_Attributes_RemediationProcedure: str + Requirements_Attributes_AuditProcedure: str + Requirements_Attributes_AdditionalInformation: str + Requirements_Attributes_References: str + Requirements_Attributes_DefaultValue: str + Status: str + StatusExtended: str + ResourceId: str + ResourceName: str + CheckId: str + Muted: bool + + # TODO: Create a parent class for the common fields of CIS and have the specific classes from each provider to inherit from it. # It is not done yet because it is needed to respect the current order of the fields in the output file. diff --git a/tests/lib/outputs/compliance/compliance_test.py b/tests/lib/outputs/compliance/compliance_test.py index d9458bc6b0..b2fc94488f 100644 --- a/tests/lib/outputs/compliance/compliance_test.py +++ b/tests/lib/outputs/compliance/compliance_test.py @@ -330,3 +330,55 @@ class TestCompliance: "CIS-2.0": ["2.1.3"], "CIS-2.1": ["2.1.3"], } + + def test_get_check_compliance_github(self): + check_compliance = [ + Compliance( + Framework="CIS", + Provider="Github", + Version="1.0", + Description="This document provides prescriptive guidance for establishing a secure configuration posture for securing GitHub.", + Requirements=[ + Compliance_Requirement( + Checks=[], + Id="1.1.11", + Description="Ensure all open comments are resolved before allowing code change merging", + Attributes=[ + CIS_Requirement_Attribute( + Section="1.1", + Profile="Level 2", + AssessmentStatus="Manual", + Description='Organizations should enforce a "no open comments" policy before allowing code change merging.', + RationaleStatement="In an open code change proposal, reviewers can leave comments containing their questions and suggestions. These comments can also include potential bugs and security issues. Requiring all comments on a code change proposal to be resolved before it can be merged ensures that every concern is properly addressed or acknowledged before the new code changes are introduced to the code base.", + ImpactStatement="Code change proposals containing open comments would not be able to be merged into the code base.", + RemediationProcedure='For each code repository in use, require open comments to be resolved before the relevant code change can be merged by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the "Code and automation" section of the sidebar, click **Branches**.\n 4. Next to "Branch protection rules", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn\'t, click **Add rule**.\n 5. If you add the rule, under "Branch name pattern", type the branch name or pattern you want to protect.\n 6. Select **Require conversation resolution before merging**.\n 7. Click **Create** or **Save changes**.', + AuditProcedure='For every code repository in use, verify that each merged code change does not contain open, unattended comments by performing the following:\n \n\n 1. On GitHub.com, navigate to the main page of the repository.\n 2. Under your repository name, click **Settings**.\n 3. In the "Code and automation" section of the sidebar, click **Branches**.\n 4. Next to "Branch protection rules", verify that there is at least one rule for your main branch. If there is, click **Edit** to its right. If there isn\'t, you are not compliant.\n 5. Ensure that **Require conversation resolution before merging** is checked.', + AdditionalInformation="", + References="", + ) + ], + ) + ], + ) + ] + + finding = Check_Report( + metadata=load_check_metadata( + f"{path.dirname(path.realpath(__file__))}/../fixtures/metadata.json" + ).json(), + resource={}, + ) + finding.resource_details = "Test resource details" + finding.resource_id = "test-resource" + finding.resource_arn = "test-arn" + finding.region = "eu-west-1" + finding.status = "PASS" + finding.status_extended = "This is a test" + + bulk_checks_metadata = {} + bulk_checks_metadata["iam_user_accesskey_unused"] = mock.MagicMock() + bulk_checks_metadata["iam_user_accesskey_unused"].Compliance = check_compliance + + assert get_check_compliance(finding, "github", bulk_checks_metadata) == { + "CIS-1.0": ["1.1.11"], + } diff --git a/util/generate_compliance_json_from_csv_for_cis10_github.py b/util/generate_compliance_json_from_csv_for_cis10_github.py new file mode 100644 index 0000000000..3297c70640 --- /dev/null +++ b/util/generate_compliance_json_from_csv_for_cis10_github.py @@ -0,0 +1,40 @@ +import csv +import json +import sys + +# Convert a CSV file following the CIS 1.0 GitHub benchmark into a Prowler v3.0 Compliance JSON file +# CSV fields: +# Id, Title,Checks,Attributes_Section,Attributes_Level,Attributes_AssessmentStatus,Attributes_Description,Attributes_RationalStatement,Attributes_ImpactStatement,Attributes_RemediationProcedure,Attributes_AuditProcedure,Attributes_AdditionalInformation,Attributes_References + +# get the CSV filename to convert from +file_name = sys.argv[1] + +# read the CSV file rows and use the column fields to form the Prowler compliance JSON file 'cis_1.0_github.json' +output = {"Framework": "CIS-GitHub", "Version": "1.5", "Requirements": []} +with open(file_name, newline="", encoding="utf-8") as f: + reader = csv.reader(f, delimiter=",") + for row in reader: + attribute = { + "Section": row[3], + "Profile": row[4], + "AssessmentStatus": row[5], + "Description": row[6], + "RationaleStatement": row[7], + "ImpactStatement": row[8], + "RemediationProcedure": row[9], + "AuditProcedure": row[10], + "AdditionalInformation": row[11], + "References": row[12], + } + output["Requirements"].append( + { + "Id": row[0], + "Description": row[1], + "Checks": list(map(str.strip, row[2].split(","))), + "Attributes": [attribute], + } + ) + +# Write the output Prowler compliance JSON file 'cis_1.0_github.json' locally +with open("cis_1.0_github.json", "w", encoding="utf-8") as outfile: + json.dump(output, outfile, indent=4, ensure_ascii=False) From c5a9b63970d07f1baf8822ccee8b75df28391fe2 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 14 May 2025 11:36:27 +0200 Subject: [PATCH 315/359] fix: UID Filter Improvement (#7741) Co-authored-by: sumit_chaturvedi --- ui/CHANGELOG.md | 1 + ui/app/(prowler)/findings/page.tsx | 22 ++++++++-- .../ui/custom/custom-dropdown-filter.tsx | 43 +++++++++++++------ ui/types/filters.ts | 3 ++ ui/types/providers.ts | 6 +++ 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 3dc0f8ba35..b6fc46f57b 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Add a new chart to show the split between passed and failed findings. [(#7680)](https://github.com/prowler-cloud/prowler/pull/7680) - Added `Accordion` component. [(#7700)](https://github.com/prowler-cloud/prowler/pull/7700) +- Improve `Provider UID` filter by adding more context and enhancing the UI/UX. [(#7741)](https://github.com/prowler-cloud/prowler/pull/7741) - Added an AWS CloudFormation Quick Link to the IAM Role credentials step [(#7735)](https://github.com/prowler-cloud/prowler/pull/7735) ### 🐞 Fixes diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index 0ddf609b6e..a894210fa8 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -14,7 +14,7 @@ import { import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { createDict } from "@/lib"; -import { ProviderProps } from "@/types"; +import { ProviderAccountProps, ProviderProps } from "@/types"; import { FindingProps, ScanProps, SearchParamsProps } from "@/types/components"; export default async function Findings({ @@ -73,14 +73,29 @@ export default async function Findings({ // Get findings data // Extract provider UIDs - const providerUIDs = Array.from( + const providerUIDs: string[] = Array.from( new Set( providersData?.data - ?.map((provider: ProviderProps) => provider.attributes.uid) + ?.map((provider: ProviderProps) => provider.attributes?.uid) .filter(Boolean), ), ); + const providerDetails: Array<{ [uid: string]: ProviderAccountProps }> = + providerUIDs.map((uid) => { + const provider = providersData.data.find( + (p: { attributes: { uid: string } }) => p.attributes?.uid === uid, + ); + + return { + [uid]: { + provider: provider?.attributes?.provider || "", + uid: uid, + alias: provider?.attributes?.alias ?? null, + }, + }; + }); + // Extract scan UUIDs with "completed" state and more than one resource const completedScans = scansData?.data ?.filter( @@ -122,6 +137,7 @@ export default async function Findings({ key: "provider_uid__in", labelCheckboxGroup: "Provider UID", values: providerUIDs, + valueLabelMapping: providerDetails, }, { key: "scan__in", diff --git a/ui/components/ui/custom/custom-dropdown-filter.tsx b/ui/components/ui/custom/custom-dropdown-filter.tsx index 7f659d9c13..ee18bab9bc 100644 --- a/ui/components/ui/custom/custom-dropdown-filter.tsx +++ b/ui/components/ui/custom/custom-dropdown-filter.tsx @@ -18,6 +18,8 @@ import { PlusCircleIcon } from "@/components/icons"; import { useUrlFilters } from "@/hooks/use-url-filters"; import { CustomDropdownFilterProps } from "@/types"; +import { EntityInfoShort } from "../entities"; + const filterSelectedClass = "inline-flex items-center border py-1 text-xs transition-colors border-transparent bg-default-500 text-secondary-foreground hover:bg-default-500/80 rounded-md px-2 font-normal"; @@ -192,18 +194,35 @@ export const CustomDropdownFilter: React.FC = ({ hideScrollBar className="flex max-h-96 max-w-56 flex-col gap-y-2 py-2" > - {memoizedFilterValues.map((value) => ( - - {value} - - ))} + {memoizedFilterValues.map((value) => { + // Find the corresponding entity from valueLabelMapping + const matchingEntry = filter.valueLabelMapping?.find( + (entry) => entry[value], + ); + const entity = matchingEntry?.[value]; + + return ( + + {entity ? ( + + ) : ( + value + )} + + ); + })}
    diff --git a/ui/types/filters.ts b/ui/types/filters.ts index 944706f7aa..a8fb78dde9 100644 --- a/ui/types/filters.ts +++ b/ui/types/filters.ts @@ -1,7 +1,10 @@ +import { ProviderAccountProps } from "./providers"; + export interface FilterOption { key: string; labelCheckboxGroup: string; values: string[]; + valueLabelMapping?: Array<{ [uid: string]: ProviderAccountProps }>; } export interface CustomDropdownFilterProps { diff --git a/ui/types/providers.ts b/ui/types/providers.ts index 50353125e7..6bac15262c 100644 --- a/ui/types/providers.ts +++ b/ui/types/providers.ts @@ -45,6 +45,12 @@ export interface ProviderProps { groupNames?: string[]; } +export interface ProviderAccountProps { + provider: ProviderType; + uid: string; + alias: string; +} + export interface ProviderOverviewProps { data: { type: "provider-overviews"; From 8431ce42a12c09dbf0c6c2178de5a75323719f22 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 13:29:08 +0200 Subject: [PATCH 316/359] feat(organization): add new check `organization_members_mfa_required` (#6304) Co-authored-by: MrCloudSec --- README.md | 2 +- poetry.lock | 26 +++++ prowler/CHANGELOG.md | 1 + prowler/__main__.py | 1 - .../__init__.py | 0 ...ization_members_mfa_required.metadata.json | 30 ++++++ .../organization_members_mfa_required.py | 36 +++++++ .../organization/organization_service.py | 11 ++ .../organization_members_mfa_required_test.py | 100 ++++++++++++++++++ .../organization/organization_service_test.py | 2 + 10 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/github/services/organization/organization_members_mfa_required/__init__.py create mode 100644 prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.metadata.json create mode 100644 prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.py create mode 100644 tests/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required_test.py diff --git a/README.md b/README.md index 221a29d35e..7fef33c6ae 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ prowler dashboard | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | -| GitHub | 2 | 1 | 1 | 0 | +| GitHub | 3 | 2 | 1 | 0 | | M365 | 44 | 2 | 2 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | diff --git a/poetry.lock b/poetry.lock index 2734a604dd..01c3b39bd3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3969,6 +3969,32 @@ cffi = ">=1.4.1" docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + [[package]] name = "pyparsing" version = "3.2.3" diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index fdd357b1c2..3baeb7ceb8 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) +- Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) ### Fixed diff --git a/prowler/__main__.py b/prowler/__main__.py index 6aa74c98ab..e22d7b7fa6 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -799,7 +799,6 @@ def prowler(): cis = GithubCIS( findings=finding_outputs, compliance=bulk_compliance_frameworks[compliance_name], - create_file_descriptor=True, file_path=filename, ) generated_outputs["compliance"].append(cis) diff --git a/prowler/providers/github/services/organization/organization_members_mfa_required/__init__.py b/prowler/providers/github/services/organization/organization_members_mfa_required/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.metadata.json b/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.metadata.json new file mode 100644 index 0000000000..cb1d67e96e --- /dev/null +++ b/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "organization_members_mfa_required", + "CheckTitle": "Check if organization members are required to have MFA enabled.", + "CheckType": [], + "ServiceName": "organization", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "GitHubOrganization", + "Description": "Ensure that all organization members are required to have multi-factor authentication (MFA) enabled. Enforcing MFA for all organization members helps protect the organization's resources and data from unauthorized access and security breaches.", + "Risk": "Without Multi-Factor Authentication (MFA), user accounts are vulnerable to unauthorized access if their passwords are compromised. This can lead to unauthorized actions such as data theft, malicious code commits, and repository manipulation, potentially compromising the organization's source code and intellectual property.", + "RelatedUrl": "https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-two-factor-authentication-for-your-organization/requiring-two-factor-authentication-in-your-organization", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Mandate the use of MFA for all organization members. This significantly enhances account security by adding an additional layer of protection beyond a username and password. MFA ensures that even if a password is compromised, unauthorized access to user accounts and repositories is prevented, safeguarding sensitive data and critical assets.", + "Url": "https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-two-factor-authentication-for-your-organization/preparing-to-require-two-factor-authentication-in-your-organization" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.py b/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.py new file mode 100644 index 0000000000..e18c127c0d --- /dev/null +++ b/prowler/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required.py @@ -0,0 +1,36 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.organization.organization_client import ( + organization_client, +) + + +class organization_members_mfa_required(Check): + """Check if organization members are required to have two-factor authentication enabled. + + This class verifies whether each organization requires its members to have two-factor authentication enabled. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Organization Members MFA Required check. + + Iterates over all organizations and checks if members are required to have two-factor authentication enabled. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for org in organization_client.organizations.values(): + if org.mfa_required is not None: + report = CheckReportGithub(metadata=self.metadata(), resource=org) + report.status = "FAIL" + report.status_extended = f"Organization {org.name} does not require members to have two-factor authentication enabled." + + if org.mfa_required: + report.status = "PASS" + report.status_extended = f"Organization {org.name} does require members to have two-factor authentication enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/organization/organization_service.py b/prowler/providers/github/services/organization/organization_service.py index 64c2e7c0d8..3f8f8dca95 100644 --- a/prowler/providers/github/services/organization/organization_service.py +++ b/prowler/providers/github/services/organization/organization_service.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import BaseModel from prowler.lib.logger import logger @@ -15,9 +17,17 @@ class Organization(GithubService): try: for client in self.clients: for org in client.get_user().get_orgs(): + try: + require_mfa = org.two_factor_requirement_enabled + except Exception as error: + require_mfa = None + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) organizations[org.id] = Org( id=org.id, name=org.login, + mfa_required=require_mfa, ) except Exception as error: logger.error( @@ -31,3 +41,4 @@ class Org(BaseModel): id: int name: str + mfa_required: Optional[bool] = False diff --git a/tests/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required_test.py b/tests/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required_test.py new file mode 100644 index 0000000000..823c0f294f --- /dev/null +++ b/tests/providers/github/services/organization/organization_members_mfa_required/organization_members_mfa_required_test.py @@ -0,0 +1,100 @@ +from unittest import mock + +from prowler.providers.github.services.organization.organization_service import Org +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_organization_members_mfa_required: + def test_no_organizations(self): + organization_client = mock.MagicMock + organization_client.organizations = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required.organization_client", + new=organization_client, + ), + ): + from prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required import ( + organization_members_mfa_required, + ) + + check = organization_members_mfa_required() + result = check.execute() + assert len(result) == 0 + + def test_organization_mfa_disabled(self): + organization_client = mock.MagicMock + org_name = "test-organization" + organization_client.organizations = { + 1: Org( + id=1, + name=org_name, + mfa_required=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required.organization_client", + new=organization_client, + ), + ): + from prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required import ( + organization_members_mfa_required, + ) + + check = organization_members_mfa_required() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "test-organization" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Organization {org_name} does not require members to have two-factor authentication enabled." + ) + + def test_one_organization_securitymd(self): + organization_client = mock.MagicMock + org_name = "test-organization" + organization_client.organizations = { + 1: Org( + id=1, + name=org_name, + mfa_required=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required.organization_client", + new=organization_client, + ), + ): + from prowler.providers.github.services.organization.organization_members_mfa_required.organization_members_mfa_required import ( + organization_members_mfa_required, + ) + + check = organization_members_mfa_required() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "test-organization" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Organization {org_name} does require members to have two-factor authentication enabled." + ) diff --git a/tests/providers/github/services/organization/organization_service_test.py b/tests/providers/github/services/organization/organization_service_test.py index 02dabf80ff..7720841698 100644 --- a/tests/providers/github/services/organization/organization_service_test.py +++ b/tests/providers/github/services/organization/organization_service_test.py @@ -12,6 +12,7 @@ def mock_list_organizations(_): 1: Org( id=1, name="test-organization", + mfa_required=True, ), } @@ -33,3 +34,4 @@ class Test_Repository_Service: repository_service = Organization(set_mocked_github_provider()) assert len(repository_service.organizations) == 1 assert repository_service.organizations[1].name == "test-organization" + assert repository_service.organizations[1].mfa_required From beb7a53efe25158a872d21bc8cdef6ee63c94db4 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 13:42:59 +0200 Subject: [PATCH 317/359] feat(repository): add new check `repository_default_branch_protection_enabled` (#6161) Co-authored-by: MrCloudSec Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...lt_branch_protection_enabled.metadata.json | 30 +++++ ...itory_default_branch_protection_enabled.py | 38 ++++++ .../services/repository/repository_service.py | 6 + ...changes_multi_approval_requirement_test.py | 3 + ..._default_branch_protection_enabled_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 8 files changed, 190 insertions(+) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_enabled/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 3baeb7ceb8..916005d084 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) +- Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.metadata.json new file mode 100644 index 0000000000..8ba7caa87a --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_protection_enabled", + "CheckTitle": "Check if branch protection is enforced on the default branch ", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "github:user-id:repository/repository-name", + "Severity": "critical", + "ResourceType": "GitHubRepository", + "Description": "Ensure branch protection is enforced on the default branch", + "Risk": "The absence of branch protection on the default branch increases the risk of unauthorized, unreviewed, or untested changes being merged. This can compromise the stability, security, and reliability of the codebase, which is especially critical for production deployments.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Apply branch protection rules to the default branch to ensure it is safeguarded against unauthorized or improper modifications. This helps maintain code quality, enforces proper review and testing procedures, and reduces the risk of accidental or malicious changes.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule#creating-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.py b/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.py new file mode 100644 index 0000000000..a6c9be5a37 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled.py @@ -0,0 +1,38 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_protection_enabled(Check): + """Check if a repository enforces default branch protection + + This class verifies whether each repository enforces default branch protection. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Enforces Default Branch Protection check + + Iterates over all repositories and checks if they enforce default branch protection. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.default_branch_protection is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = f"Repository {repo.name} does not enforce branch protection on default branch ({repo.default_branch})." + + if repo.default_branch_protection: + report.status = "PASS" + report.status_extended = f"Repository {repo.name} does enforce branch protection on default branch ({repo.default_branch})." + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index d2ab5d3658..6070e4cb22 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -32,6 +32,7 @@ class Repository(GithubService): require_pr = False approval_cnt = 0 + branch_protection = False try: branch = repo.get_branch(default_branch) if branch.protected: @@ -45,13 +46,16 @@ class Repository(GithubService): if require_pr else 0 ) + branch_protection = True except Exception as error: if "404" in str(error): require_pr = False approval_cnt = 0 + branch_protection = False else: require_pr = None approval_cnt = None + branch_protection = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -65,6 +69,7 @@ class Repository(GithubService): securitymd=securitymd_exists, require_pull_request=require_pr, approval_count=approval_cnt, + default_branch_protection=branch_protection, ) except Exception as error: @@ -80,6 +85,7 @@ class Repo(BaseModel): id: int name: str full_name: str + default_branch_protection: Optional[bool] default_branch: str private: bool securitymd: Optional[bool] diff --git a/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py b/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py index ba0b28e673..4378ccae95 100644 --- a/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py +++ b/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py @@ -35,6 +35,7 @@ class Test_repository_code_changes_multi_approval_requirement: id=1, name=repo_name, full_name="account-name/repo1", + default_branch_protection=False, default_branch="main", private=False, securitymd=False, @@ -76,6 +77,7 @@ class Test_repository_code_changes_multi_approval_requirement: id=1, name=repo_name, full_name="account-name/repo1", + default_branch_protection=False, default_branch="master", private=False, securitymd=False, @@ -117,6 +119,7 @@ class Test_repository_code_changes_multi_approval_requirement: id=1, name=repo_name, full_name="account-name/repo1", + default_branch_protection=True, default_branch="master", private=False, securitymd=True, diff --git a/tests/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled_test.py b/tests/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled_test.py new file mode 100644 index 0000000000..3723863298 --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_protection_enabled/repository_default_branch_protection_enabled_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_protection_enabled_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled import ( + repository_default_branch_protection_enabled, + ) + + check = repository_default_branch_protection_enabled() + result = check.execute() + assert len(result) == 0 + + def test_without_default_branch_protection(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + private=False, + default_branch_protection=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled import ( + repository_default_branch_protection_enabled, + ) + + check = repository_default_branch_protection_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not enforce branch protection on default branch ({default_branch})." + ) + + def test_default_branch_protection(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + default_branch_protection=True, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_enabled.repository_default_branch_protection_enabled import ( + repository_default_branch_protection_enabled, + ) + + check = repository_default_branch_protection_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does enforce branch protection on default branch ({default_branch})." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index bc1f709ead..d03853423e 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -13,6 +13,7 @@ def mock_list_repositories(_): id=1, name="repo1", full_name="account-name/repo1", + default_branch_protection=True, default_branch="main", private=False, securitymd=True, @@ -41,6 +42,7 @@ class Test_Repository_Service: assert repository_service.repositories[1].name == "repo1" assert repository_service.repositories[1].full_name == "account-name/repo1" assert repository_service.repositories[1].private is False + assert repository_service.repositories[1].default_branch == "main" assert repository_service.repositories[1].securitymd assert repository_service.repositories[1].require_pull_request assert repository_service.repositories[1].approval_count == 2 From 5a9ccd60a01f03544abb68291eb886e2cea3a010 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 14:37:27 +0200 Subject: [PATCH 318/359] feat(repository): add new check `repository_default_branch_requires_linear_history` (#6162) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 3 +- .../__init__.py | 0 ...anch_requires_linear_history.metadata.json | 30 +++++ ..._default_branch_requires_linear_history.py | 38 ++++++ .../__init__.py | 0 ...requires_multiple_approvals.metadata.json} | 2 +- ...ult_branch_requires_multiple_approvals.py} | 2 +- .../services/repository/repository_service.py | 14 ++- ...ult_branch_requires_linear_history_test.py | 110 ++++++++++++++++++ ...ranch_requires_multiple_approvals_test.py} | 34 +++--- .../repository/repository_service_test.py | 2 + 11 files changed, 210 insertions(+), 25 deletions(-) rename prowler/providers/github/services/repository/{repository_code_changes_multi_approval_requirement => repository_default_branch_requires_linear_history}/__init__.py (100%) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/__init__.py rename prowler/providers/github/services/repository/{repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json => repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.metadata.json} (95%) rename prowler/providers/github/services/repository/{repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py => repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.py} (95%) create mode 100644 tests/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history_test.py rename tests/providers/github/services/repository/{repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py => repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals_test.py} (75%) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 916005d084..130a3a6ba7 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -9,8 +9,9 @@ All notable changes to the **Prowler SDK** are documented in this file. - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) -- Add `repository_code_changes_multi_approval_requirement` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) +- Add `repository_default_branch_requires_multiple_approvals` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) +- Add `repository_default_branch_requires_linear_history` check for GitHub provider. [(#6162)](https://github.com/prowler-cloud/prowler/pull/6162) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/__init__.py similarity index 100% rename from prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/__init__.py rename to prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/__init__.py diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.metadata.json new file mode 100644 index 0000000000..b33d6de467 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_requires_linear_history", + "CheckTitle": "Check if repository default branch requires linear history", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "GithubRepository", + "Description": "Ensure that the repository default branch requires linear history.", + "Risk": "Allowing non-linear history can result in a cluttered and difficult-to-trace Git history, making it harder to identify specific changes, debug issues, and understand the sequence of development. This increases the risk of errors, inconsistencies, and bugs, especially in production environments.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-linear-history", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enforce a linear history by requiring rebase or squash merges for pull requests. This will create a clean, chronological commit history, making it easier to track changes, revert modifications, and troubleshoot any issues that arise.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.py b/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.py new file mode 100644 index 0000000000..a06c8b4a3f --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history.py @@ -0,0 +1,38 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_requires_linear_history(Check): + """Check if a repository requires linear history on default branch + + This class verifies whether each repository requires linear history on the default branch. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Merging Requires Linear History check + + Iterates over all repositories and checks if they require linear history on the default branch. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.required_linear_history is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = f"Repository {repo.name} does not require linear history on default branch ({repo.default_branch})." + + if repo.required_linear_history: + report.status = "PASS" + report.status_extended = f"Repository {repo.name} does require linear history on default branch ({repo.default_branch})." + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.metadata.json similarity index 95% rename from prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json rename to prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.metadata.json index 8390543480..4de957cb40 100644 --- a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.metadata.json +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.metadata.json @@ -1,6 +1,6 @@ { "Provider": "github", - "CheckID": "repository_code_changes_multi_approval_requirement", + "CheckID": "repository_default_branch_requires_multiple_approvals", "CheckTitle": "Check if repositories require at least 2 code changes approvals", "CheckType": [], "ServiceName": "repository", diff --git a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py b/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.py similarity index 95% rename from prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py rename to prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.py index 599b77a6f5..ac75115010 100644 --- a/prowler/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement.py +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals.py @@ -6,7 +6,7 @@ from prowler.providers.github.services.repository.repository_client import ( ) -class repository_code_changes_multi_approval_requirement(Check): +class repository_default_branch_requires_multiple_approvals(Check): """Check if a repository enforces at least 2 approvals for code changes This class verifies whether each repository enforces at least 2 approvals for code changes. diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 6070e4cb22..28ba63e7ff 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -33,6 +33,7 @@ class Repository(GithubService): require_pr = False approval_cnt = 0 branch_protection = False + required_linear_history = False try: branch = repo.get_branch(default_branch) if branch.protected: @@ -46,16 +47,17 @@ class Repository(GithubService): if require_pr else 0 ) + required_linear_history = ( + protection.required_linear_history + ) branch_protection = True except Exception as error: - if "404" in str(error): - require_pr = False - approval_cnt = 0 - branch_protection = False - else: + # If the branch is not found, it is not protected + if "404" not in str(error): require_pr = None approval_cnt = None branch_protection = None + required_linear_history = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -69,6 +71,7 @@ class Repository(GithubService): securitymd=securitymd_exists, require_pull_request=require_pr, approval_count=approval_cnt, + required_linear_history=required_linear_history, default_branch_protection=branch_protection, ) @@ -90,4 +93,5 @@ class Repo(BaseModel): private: bool securitymd: Optional[bool] require_pull_request: Optional[bool] + required_linear_history: Optional[bool] approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history_test.py b/tests/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history_test.py new file mode 100644 index 0000000000..5759697999 --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_requires_linear_history/repository_default_branch_requires_linear_history_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_requires_linear_history_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history import ( + repository_default_branch_requires_linear_history, + ) + + check = repository_default_branch_requires_linear_history() + result = check.execute() + assert len(result) == 0 + + def test_linear_history_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + required_linear_history=False, + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history import ( + repository_default_branch_requires_linear_history, + ) + + check = repository_default_branch_requires_linear_history() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not require linear history on default branch ({default_branch})." + ) + + def test_linear_history_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + required_linear_history=True, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_linear_history.repository_default_branch_requires_linear_history import ( + repository_default_branch_requires_linear_history, + ) + + check = repository_default_branch_requires_linear_history() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does require linear history on default branch ({default_branch})." + ) diff --git a/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py b/tests/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals_test.py similarity index 75% rename from tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py rename to tests/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals_test.py index 4378ccae95..be8905fc7d 100644 --- a/tests/providers/github/services/repository/repository_code_changes_multi_approval_requirement/repository_code_changes_multi_approval_requirement_test.py +++ b/tests/providers/github/services/repository/repository_default_branch_requires_multiple_approvals/repository_default_branch_requires_multiple_approvals_test.py @@ -4,7 +4,7 @@ from prowler.providers.github.services.repository.repository_service import Repo from tests.providers.github.github_fixtures import set_mocked_github_provider -class Test_repository_code_changes_multi_approval_requirement: +class Test_repository_default_branch_requires_multiple_approvals: def test_no_repositories(self): repository_client = mock.MagicMock repository_client.repositories = {} @@ -15,15 +15,15 @@ class Test_repository_code_changes_multi_approval_requirement: return_value=set_mocked_github_provider(), ), mock.patch( - "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + "prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals.repository_client", new=repository_client, ), ): - from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( - repository_code_changes_multi_approval_requirement, + from prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals import ( + repository_default_branch_requires_multiple_approvals, ) - check = repository_code_changes_multi_approval_requirement() + check = repository_default_branch_requires_multiple_approvals() result = check.execute() assert len(result) == 0 @@ -50,15 +50,15 @@ class Test_repository_code_changes_multi_approval_requirement: return_value=set_mocked_github_provider(), ), mock.patch( - "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + "prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals.repository_client", new=repository_client, ), ): - from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( - repository_code_changes_multi_approval_requirement, + from prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals import ( + repository_default_branch_requires_multiple_approvals, ) - check = repository_code_changes_multi_approval_requirement() + check = repository_default_branch_requires_multiple_approvals() result = check.execute() assert len(result) == 1 assert result[0].resource_id == 1 @@ -92,15 +92,15 @@ class Test_repository_code_changes_multi_approval_requirement: return_value=set_mocked_github_provider(), ), mock.patch( - "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + "prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals.repository_client", new=repository_client, ), ): - from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( - repository_code_changes_multi_approval_requirement, + from prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals import ( + repository_default_branch_requires_multiple_approvals, ) - check = repository_code_changes_multi_approval_requirement() + check = repository_default_branch_requires_multiple_approvals() result = check.execute() assert len(result) == 1 assert result[0].resource_id == 1 @@ -134,15 +134,15 @@ class Test_repository_code_changes_multi_approval_requirement: return_value=set_mocked_github_provider(), ), mock.patch( - "prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement.repository_client", + "prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals.repository_client", new=repository_client, ), ): - from prowler.providers.github.services.repository.repository_code_changes_multi_approval_requirement.repository_code_changes_multi_approval_requirement import ( - repository_code_changes_multi_approval_requirement, + from prowler.providers.github.services.repository.repository_default_branch_requires_multiple_approvals.repository_default_branch_requires_multiple_approvals import ( + repository_default_branch_requires_multiple_approvals, ) - check = repository_code_changes_multi_approval_requirement() + check = repository_default_branch_requires_multiple_approvals() result = check.execute() assert len(result) == 1 assert result[0].resource_id == 1 diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index d03853423e..970e93a76b 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -18,6 +18,7 @@ def mock_list_repositories(_): private=False, securitymd=True, require_pull_request=True, + required_linear_history=True, approval_count=2, ), } @@ -44,5 +45,6 @@ class Test_Repository_Service: assert repository_service.repositories[1].private is False assert repository_service.repositories[1].default_branch == "main" assert repository_service.repositories[1].securitymd + assert repository_service.repositories[1].required_linear_history assert repository_service.repositories[1].require_pull_request assert repository_service.repositories[1].approval_count == 2 From 600813fb9944b8f19ab0c5f28f8fe1bc82dd06fc Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Wed, 14 May 2025 15:19:41 +0200 Subject: [PATCH 319/359] fix: force z-index componet select provider (#7744) Co-authored-by: StylusFrost --- ui/components/filters/custom-select-provider.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/components/filters/custom-select-provider.tsx b/ui/components/filters/custom-select-provider.tsx index 818c881f88..89bd537745 100644 --- a/ui/components/filters/custom-select-provider.tsx +++ b/ui/components/filters/custom-select-provider.tsx @@ -74,6 +74,7 @@ export const CustomSelectProvider: React.FC = () => { placeholder="Select a provider" classNames={{ selectorIcon: "right-2", + label: "!z-0", }} label="Provider" labelPlacement="inside" From 8f9bdae2b71b1d8e85f2bccc9ff4d29915282c20 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 14 May 2025 16:48:47 +0200 Subject: [PATCH 320/359] feat(repository): add new check `repository_default_branch_disallows_force_push` (#6197) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ..._branch_disallows_force_push.metadata.json | 30 +++++ ...ory_default_branch_disallows_force_push.py | 42 +++++++ .../services/repository/repository_service.py | 12 +- ...efault_branch_disallows_force_push_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 7 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 130a3a6ba7..f2771630ad 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_requires_multiple_approvals` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) - Add `repository_default_branch_requires_linear_history` check for GitHub provider. [(#6162)](https://github.com/prowler-cloud/prowler/pull/6162) +- Add `repository_default_branch_disallows_force_push` check for GitHub provider. [(#6197)](https://github.com/prowler-cloud/prowler/pull/6197) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.metadata.json new file mode 100644 index 0000000000..5cff05ec13 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_disallows_force_push", + "CheckTitle": "Check if repository denies force push", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "GithubRepository", + "Description": "Ensure that the repository denies force push to protected branches.", + "Risk": "Permitting force pushes to branches can lead to accidental or intentional overwrites of the commit history, resulting in potential data loss, code inconsistencies, or the introduction of malicious changes. This compromises the stability and security of the repository.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#allow-force-pushes", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable force pushes on protected branches to preserve the commit history and ensure the integrity of the repository. This measure helps prevent unintentional data loss and protects the repository from malicious changes.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.py b/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.py new file mode 100644 index 0000000000..2183b84a79 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_disallows_force_push(Check): + """Check if a repository denies force push + + This class verifies whether each repository denies force push. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Denies Force Push check + + Iterates over all repositories and checks if they deny force push. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.allow_force_pushes is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does allow force push." + ) + + if not repo.allow_force_pushes: + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does deny force push." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 28ba63e7ff..7e6054a79e 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -34,6 +34,7 @@ class Repository(GithubService): approval_cnt = 0 branch_protection = False required_linear_history = False + allow_force_pushes = True try: branch = repo.get_branch(default_branch) if branch.protected: @@ -50,14 +51,21 @@ class Repository(GithubService): required_linear_history = ( protection.required_linear_history ) + allow_force_pushes = protection.allow_force_pushes branch_protection = True except Exception as error: # If the branch is not found, it is not protected - if "404" not in str(error): + if "404" in str(error): + logger.warning( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + # Any other error, we cannot know if the branch is protected or not + else: require_pr = None approval_cnt = None branch_protection = None required_linear_history = None + allow_force_pushes = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -72,6 +80,7 @@ class Repository(GithubService): require_pull_request=require_pr, approval_count=approval_cnt, required_linear_history=required_linear_history, + allow_force_pushes=allow_force_pushes, default_branch_protection=branch_protection, ) @@ -94,4 +103,5 @@ class Repo(BaseModel): securitymd: Optional[bool] require_pull_request: Optional[bool] required_linear_history: Optional[bool] + allow_force_pushes: Optional[bool] approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push_test.py b/tests/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push_test.py new file mode 100644 index 0000000000..a9da35d0fe --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_disallows_force_push/repository_default_branch_disallows_force_push_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_disallows_force_push_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push import ( + repository_default_branch_disallows_force_push, + ) + + check = repository_default_branch_disallows_force_push() + result = check.execute() + assert len(result) == 0 + + def test_allow_force_push_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + allow_force_pushes=True, + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push import ( + repository_default_branch_disallows_force_push, + ) + + check = repository_default_branch_disallows_force_push() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does allow force push." + ) + + def test_allow_force_push_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + allow_force_pushes=False, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_disallows_force_push.repository_default_branch_disallows_force_push import ( + repository_default_branch_disallows_force_push, + ) + + check = repository_default_branch_disallows_force_push() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does deny force push." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index 970e93a76b..0bdd615497 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -19,6 +19,7 @@ def mock_list_repositories(_): securitymd=True, require_pull_request=True, required_linear_history=True, + allow_force_pushes=True, approval_count=2, ), } @@ -47,4 +48,5 @@ class Test_Repository_Service: assert repository_service.repositories[1].securitymd assert repository_service.repositories[1].required_linear_history assert repository_service.repositories[1].require_pull_request + assert repository_service.repositories[1].allow_force_pushes assert repository_service.repositories[1].approval_count == 2 From 1c874d1283cf61cca99d70981c450dcfc709ccf5 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 15 May 2025 08:33:36 +0200 Subject: [PATCH 321/359] feat(repository): add new check `repository_default_branch_deletion_disabled` (#6200) Co-authored-by: MrCloudSec Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ult_branch_deletion_disabled.metadata.json | 30 +++++ ...sitory_default_branch_deletion_disabled.py | 42 +++++++ .../services/repository/repository_service.py | 5 + ...y_default_branch_deletion_disabled_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 7 files changed, 190 insertions(+) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f2771630ad..8c6d158800 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) - Add `repository_default_branch_requires_linear_history` check for GitHub provider. [(#6162)](https://github.com/prowler-cloud/prowler/pull/6162) - Add `repository_default_branch_disallows_force_push` check for GitHub provider. [(#6197)](https://github.com/prowler-cloud/prowler/pull/6197) +- Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.metadata.json new file mode 100644 index 0000000000..422ff6dbe4 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_deletion_disabled", + "CheckTitle": "Check if a repository denies default branch deletion", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "GitHubRepository", + "Description": "Ensure that the repository denies default branch deletion.", + "Risk": "Allowing the deletion of protected branches by users with push access increases the risk of accidental or intentional branch removal, potentially resulting in significant data loss or disruption to the development process.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#allow-deletions", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Deny the ability to delete protected branches to ensure the preservation of critical branch data. This prevents accidental or malicious deletions and helps maintain the integrity and stability of the repository.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.py b/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.py new file mode 100644 index 0000000000..12d504a926 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_deletion_disabled(Check): + """Check if a repository denies branch deletion + + This class verifies whether each repository denies default branch deletion. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Denies Default Branch Deletion check + + Iterates over all repositories and checks if they deny default branch deletion. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.default_branch_deletion is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does allow default branch deletion." + ) + + if not repo.default_branch_deletion: + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does deny default branch deletion." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 7e6054a79e..1925a30566 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -35,6 +35,7 @@ class Repository(GithubService): branch_protection = False required_linear_history = False allow_force_pushes = True + branch_deletion = True try: branch = repo.get_branch(default_branch) if branch.protected: @@ -52,6 +53,7 @@ class Repository(GithubService): protection.required_linear_history ) allow_force_pushes = protection.allow_force_pushes + branch_deletion = protection.allow_deletions branch_protection = True except Exception as error: # If the branch is not found, it is not protected @@ -66,6 +68,7 @@ class Repository(GithubService): branch_protection = None required_linear_history = None allow_force_pushes = None + branch_deletion = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -81,6 +84,7 @@ class Repository(GithubService): approval_count=approval_cnt, required_linear_history=required_linear_history, allow_force_pushes=allow_force_pushes, + default_branch_deletion=branch_deletion, default_branch_protection=branch_protection, ) @@ -104,4 +108,5 @@ class Repo(BaseModel): require_pull_request: Optional[bool] required_linear_history: Optional[bool] allow_force_pushes: Optional[bool] + default_branch_deletion: Optional[bool] approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled_test.py b/tests/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled_test.py new file mode 100644 index 0000000000..825e4bdc6e --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_deletion_disabled/repository_default_branch_deletion_disabled_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_deletion_disabled_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled import ( + repository_default_branch_deletion_disabled, + ) + + check = repository_default_branch_deletion_disabled() + result = check.execute() + assert len(result) == 0 + + def test_allow_branch_deletion_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + default_branch_deletion=True, + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled import ( + repository_default_branch_deletion_disabled, + ) + + check = repository_default_branch_deletion_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does allow default branch deletion." + ) + + def test_allow_branch_deletion_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + default_branch_deletion=False, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_deletion_disabled.repository_default_branch_deletion_disabled import ( + repository_default_branch_deletion_disabled, + ) + + check = repository_default_branch_deletion_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does deny default branch deletion." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index 0bdd615497..da28e1269f 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -20,6 +20,7 @@ def mock_list_repositories(_): require_pull_request=True, required_linear_history=True, allow_force_pushes=True, + default_branch_deletion=True, approval_count=2, ), } @@ -49,4 +50,5 @@ class Test_Repository_Service: assert repository_service.repositories[1].required_linear_history assert repository_service.repositories[1].require_pull_request assert repository_service.repositories[1].allow_force_pushes + assert repository_service.repositories[1].default_branch_deletion assert repository_service.repositories[1].approval_count == 2 From 21f8b5dbad140040c3ba4926f6114183649257e0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 15 May 2025 11:22:58 +0200 Subject: [PATCH 322/359] fix(check): add missing `__init__.py` files (#7748) --- .../services/efs/efs_multi_az_enabled/{__int__.py => __init__.py} | 0 .../opensearch_service_domains_access_control_enabled/__init__.py | 0 .../cosmosdb/cosmosdb_account_use_aad_and_rbac/__init__.py | 0 .../services/keyvault/keyvault_key_rotation_enabled/__init__.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename prowler/providers/aws/services/efs/efs_multi_az_enabled/{__int__.py => __init__.py} (100%) create mode 100644 prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/__init__.py create mode 100644 prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/__init__.py create mode 100644 prowler/providers/azure/services/keyvault/keyvault_key_rotation_enabled/__init__.py diff --git a/prowler/providers/aws/services/efs/efs_multi_az_enabled/__int__.py b/prowler/providers/aws/services/efs/efs_multi_az_enabled/__init__.py similarity index 100% rename from prowler/providers/aws/services/efs/efs_multi_az_enabled/__int__.py rename to prowler/providers/aws/services/efs/efs_multi_az_enabled/__init__.py diff --git a/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/__init__.py b/prowler/providers/aws/services/opensearch/opensearch_service_domains_access_control_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/__init__.py b/prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/azure/services/keyvault/keyvault_key_rotation_enabled/__init__.py b/prowler/providers/azure/services/keyvault/keyvault_key_rotation_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 977c788fff4eacc74756854de9af9f78619a7f5e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 15 May 2025 15:33:49 +0200 Subject: [PATCH 323/359] feat(repository): add new check `repository_default_branch_status_checks_required` (#6204) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ranch_status_checks_required.metadata.json | 30 +++++ ...y_default_branch_status_checks_required.py | 42 +++++++ .../services/repository/repository_service.py | 7 ++ ...ault_branch_status_checks_required_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 7 files changed, 192 insertions(+) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_status_checks_required/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 8c6d158800..b1a1a2db1d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_requires_linear_history` check for GitHub provider. [(#6162)](https://github.com/prowler-cloud/prowler/pull/6162) - Add `repository_default_branch_disallows_force_push` check for GitHub provider. [(#6197)](https://github.com/prowler-cloud/prowler/pull/6197) - Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200) +- Add `repository_default_branch_status_checks_required` check for GitHub provider. [(#6204)](https://github.com/prowler-cloud/prowler/pull/6204) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.metadata.json new file mode 100644 index 0000000000..e9d846bc2f --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_status_checks_required", + "CheckTitle": "Check if repository enforces status checks to pass", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "GithubRepository", + "Description": "Ensure that the repository enforces status checks to pass before merging code into the main branch.", + "Risk": "Merging code without requiring all checks to pass increases the risk of introducing bugs, vulnerabilities, or unstable changes into the codebase. This can compromise the quality, security, and functionality of the application.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Require all predefined status checks to pass successfully before allowing code changes to be merged. This ensures that all quality, stability, and security conditions are met, reducing the likelihood of errors or vulnerabilities being introduced into the project.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.py b/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.py new file mode 100644 index 0000000000..21d6b173da --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_status_checks_required(Check): + """Check if a repository enforces status checks. + + This class verifies whether each repository enforces status checks. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository + + Iterates over all repositories and checks if they enforce status checks. + + Returns: + List[CheckReportGithub]: A list of reports for each repository. + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.status_checks is not None: + report = CheckReportGithub( + self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does not enforce status checks." + ) + + if repo.status_checks: + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does enforce status checks." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 1925a30566..c9a62f8086 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -36,6 +36,7 @@ class Repository(GithubService): required_linear_history = False allow_force_pushes = True branch_deletion = True + status_checks = False try: branch = repo.get_branch(default_branch) if branch.protected: @@ -54,6 +55,9 @@ class Repository(GithubService): ) allow_force_pushes = protection.allow_force_pushes branch_deletion = protection.allow_deletions + status_checks = ( + protection.required_status_checks is not None + ) branch_protection = True except Exception as error: # If the branch is not found, it is not protected @@ -69,6 +73,7 @@ class Repository(GithubService): required_linear_history = None allow_force_pushes = None branch_deletion = None + status_checks = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -85,6 +90,7 @@ class Repository(GithubService): required_linear_history=required_linear_history, allow_force_pushes=allow_force_pushes, default_branch_deletion=branch_deletion, + status_checks=status_checks, default_branch_protection=branch_protection, ) @@ -109,4 +115,5 @@ class Repo(BaseModel): required_linear_history: Optional[bool] allow_force_pushes: Optional[bool] default_branch_deletion: Optional[bool] + status_checks: Optional[bool] approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required_test.py b/tests/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required_test.py new file mode 100644 index 0000000000..0da7d9425f --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_status_checks_required/repository_default_branch_status_checks_required_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_status_checks_required_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import ( + repository_default_branch_status_checks_required, + ) + + check = repository_default_branch_status_checks_required() + result = check.execute() + assert len(result) == 0 + + def test_enforce_status_checks_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + status_checks=False, + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import ( + repository_default_branch_status_checks_required, + ) + + check = repository_default_branch_status_checks_required() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not enforce status checks." + ) + + def test_enforce_status_checks_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + status_checks=True, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import ( + repository_default_branch_status_checks_required, + ) + + check = repository_default_branch_status_checks_required() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does enforce status checks." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index da28e1269f..54aec2936b 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -21,6 +21,7 @@ def mock_list_repositories(_): required_linear_history=True, allow_force_pushes=True, default_branch_deletion=True, + status_checks=True, approval_count=2, ), } @@ -51,4 +52,5 @@ class Test_Repository_Service: assert repository_service.repositories[1].require_pull_request assert repository_service.repositories[1].allow_force_pushes assert repository_service.repositories[1].default_branch_deletion + assert repository_service.repositories[1].status_checks assert repository_service.repositories[1].approval_count == 2 From f5a2695c3b712757dd1b85183101d6616af776ee Mon Sep 17 00:00:00 2001 From: Ogonna Iwunze <1915636+wunzeco@users.noreply.github.com> Date: Thu, 15 May 2025 15:00:00 +0100 Subject: [PATCH 324/359] fix(check): Add support for condition with restriction on SNS endpoint (#7750) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../providers/aws/services/iam/lib/policy.py | 50 ++++++++ .../sns_topics_not_publicly_accessible.py | 11 ++ .../aws/services/iam/lib/policy_test.py | 35 ++++++ ...sns_topics_not_publicly_accessible_test.py | 107 ++++++++++++++++++ 5 files changed, 204 insertions(+) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index b1a1a2db1d..c3cd28355a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) +- Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750) --- diff --git a/prowler/providers/aws/services/iam/lib/policy.py b/prowler/providers/aws/services/iam/lib/policy.py index b45dd1bd30..e023b137b5 100644 --- a/prowler/providers/aws/services/iam/lib/policy.py +++ b/prowler/providers/aws/services/iam/lib/policy.py @@ -1,4 +1,5 @@ from ipaddress import ip_address, ip_network +import re from prowler.lib.logger import logger from prowler.providers.aws.aws_provider import read_aws_regions_file @@ -415,6 +416,55 @@ def is_condition_block_restrictive_organization( return is_condition_valid +def is_condition_block_restrictive_sns_endpoint( + condition_statement: dict, +): + """ + is_condition_block_restrictive_sns_endpoint parses the IAM Condition policy block and returns True if the condition_statement is restrictive for an endpoint, False if not. + + @param condition_statement: dict with an IAM Condition block, e.g.: + { + "StringLike": { + "SNS:Endpoint": "https://events.pagerduty.com/integration//enqueue" + } + } + + """ + is_condition_valid = False + + # The conditions must be defined in lowercase since the context key names are not case-sensitive. + # For example, including the aws:PrincipalOrgID context key is equivalent to testing for AWS:PrincipalOrgID + # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html + valid_condition_options = { + "StringEquals": [ + "sns:endpoint", + ], + "StringLike": [ + "sns:endpoint", + ], + } + + for condition_operator, condition_operator_key in valid_condition_options.items(): + if condition_operator in condition_statement: + # https://docs.aws.amazon.com/sns/latest/dg/sns-using-identity-based-policies.html#sns-policy-keys + # sns:endpoint - The URL, email address, or ARN from a Subscribe request or a previously confirmed subscription. + pattern = re.compile(r".+@[^*]+|^https:\/\/[^*]+|^arn:aws:sns:[^*]+") + for value in condition_operator_key: + # We need to transform the condition_statement into lowercase + condition_statement[condition_operator] = { + k.lower(): v + for k, v in condition_statement[condition_operator].items() + } + + if value in condition_statement[condition_operator]: + if pattern.fullmatch( + condition_statement[condition_operator][value] + ): + is_condition_valid = True + + return is_condition_valid + + def process_actions(effect, actions, target_set): """ process_actions processes the actions in the policy. diff --git a/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py b/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py index 536bf4f800..1dc0776b64 100644 --- a/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py +++ b/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py @@ -2,6 +2,7 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.iam.lib.policy import ( is_condition_block_restrictive, is_condition_block_restrictive_organization, + is_condition_block_restrictive_sns_endpoint, ) from prowler.providers.aws.services.sns.sns_client import sns_client @@ -32,6 +33,7 @@ class sns_topics_not_publicly_accessible(Check): ): condition_account = False condition_org = False + condition_endpoint = False if ( "Condition" in statement and is_condition_block_restrictive( @@ -47,6 +49,13 @@ class sns_topics_not_publicly_accessible(Check): ) ): condition_org = True + if ( + "Condition" in statement + and is_condition_block_restrictive_sns_endpoint( + statement["Condition"], + ) + ): + condition_endpoint = True if condition_account and condition_org: report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from the account {sns_client.audited_account} and an organization." @@ -54,6 +63,8 @@ class sns_topics_not_publicly_accessible(Check): report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from the account {sns_client.audited_account}." elif condition_org: report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from an organization." + elif condition_endpoint: + report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from an endpoint." else: report.status = "FAIL" report.status_extended = f"SNS topic {topic.name} is public because its policy allows public access." diff --git a/tests/providers/aws/services/iam/lib/policy_test.py b/tests/providers/aws/services/iam/lib/policy_test.py index bac84355ac..02e88739ec 100644 --- a/tests/providers/aws/services/iam/lib/policy_test.py +++ b/tests/providers/aws/services/iam/lib/policy_test.py @@ -3,9 +3,11 @@ from prowler.providers.aws.services.iam.lib.policy import ( check_full_service_access, is_condition_block_restrictive, is_condition_block_restrictive_organization, + is_condition_block_restrictive_sns_endpoint, is_condition_restricting_from_private_ip, is_policy_public, ) +import pytest TRUSTED_AWS_ACCOUNT_NUMBER = "123456789012" NON_TRUSTED_AWS_ACCOUNT_NUMBER = "111222333444" @@ -1442,6 +1444,39 @@ class Test_Policy: condition_statement = {"StringEquals": {"aws:PrincipalOrgID": ALL_ORGS}} assert not is_condition_block_restrictive_organization(condition_statement) + @pytest.mark.parametrize( + "condition_value,expected", + [ + ("*@example.com", True), + ("https://events.pagerduty.com/integration//enqueue", True), + ( + "arn:aws:sns:eu-west-2:123456789012:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7", + True, + ), + ("*@*.com", False), + ("*@*", False), + ("*@example.*", False), + ("https://events.pagerduty.com/integration/*/enqueue", False), + ("arn:aws:sns:eu-west-2:123456789012:example-topic:*", False), + ( + "arn:aws:sns:eu-west-2:*:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7", + False, + ), + ], + ) + def test_condition_parser_string_equals_sns_endpoint_str( + self, condition_value: str, expected: bool + ): + condition_statement = {"StringEquals": {"SNS:Endpoint": condition_value}} + assert ( + is_condition_block_restrictive_sns_endpoint(condition_statement) == expected + ) + + condition_statement = {"StringLike": {"SNS:Endpoint": condition_value}} + assert ( + is_condition_block_restrictive_sns_endpoint(condition_statement) == expected + ) + def test_policy_allows_cross_account_access_with_root_and_wildcard_principal(self): policy_allow_root_and_wildcard_principal = { "Statement": [ diff --git a/tests/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible_test.py b/tests/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible_test.py index 81f2cc8bad..71aa6c4477 100644 --- a/tests/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible_test.py +++ b/tests/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible_test.py @@ -1,8 +1,10 @@ +from typing import Any, Dict from unittest import mock from uuid import uuid4 from prowler.providers.aws.services.sns.sns_service import Topic from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1 +import pytest kms_key_id = str(uuid4()) topic_name = "test-topic" @@ -97,6 +99,20 @@ test_policy_restricted_principal_account_organization = { } +def generate_policy_restricted_on_sns_endpoint(endpoint: str) -> Dict[str, Any]: + return { + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": ["sns:Publish"], + "Resource": f"arn:aws:sns:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:{topic_name}", + "Condition": {"StringEquals": {"SNS:Endpoint": endpoint}}, + } + ] + } + + class Test_sns_topics_not_publicly_accessible: def test_no_topics(self): sns_client = mock.MagicMock @@ -379,3 +395,94 @@ class Test_sns_topics_not_publicly_accessible: assert result[0].resource_arn == topic_arn assert result[0].region == AWS_REGION_EU_WEST_1 assert result[0].resource_tags == [] + + @pytest.mark.parametrize( + "endpoint", + [ + ("*@example.com"), + ("user@example.com"), + ("https://events.pagerduty.com/integration/987654321/enqueue"), + ( + "arn:aws:sns:eu-west-2:123456789012:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7" + ), + ], + ) + def test_topic_public_with_sns_endpoint(self, endpoint: str): + sns_client = mock.MagicMock + sns_client.audited_account = AWS_ACCOUNT_NUMBER + sns_client.topics = [] + sns_client.topics.append( + Topic( + arn=topic_arn, + name=topic_name, + policy=generate_policy_restricted_on_sns_endpoint(endpoint=endpoint), + region=AWS_REGION_EU_WEST_1, + ) + ) + sns_client.provider = mock.MagicMock() + sns_client.provider.organizations_metadata = mock.MagicMock() + sns_client.provider.organizations_metadata.organization_id = org_id + with mock.patch( + "prowler.providers.aws.services.sns.sns_service.SNS", + sns_client, + ): + from prowler.providers.aws.services.sns.sns_topics_not_publicly_accessible.sns_topics_not_publicly_accessible import ( + sns_topics_not_publicly_accessible, + ) + + check = sns_topics_not_publicly_accessible() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SNS topic {topic_name} is not public because its policy only allows access from an endpoint." + ) + assert result[0].resource_id == topic_name + assert result[0].resource_arn == topic_arn + assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource_tags == [] + + @pytest.mark.parametrize( + "endpoint", + [ + ("*@*"), + ("https://events.pagerduty.com/integration/*/enqueue"), + ("arn:aws:sns:eu-west-2:*:example-topic:*"), + ], + ) + def test_topic_public_with_unrestricted_sns_endpoint(self, endpoint: str): + sns_client = mock.MagicMock + sns_client.audited_account = AWS_ACCOUNT_NUMBER + sns_client.topics = [] + sns_client.topics.append( + Topic( + arn=topic_arn, + name=topic_name, + policy=generate_policy_restricted_on_sns_endpoint(endpoint=endpoint), + region=AWS_REGION_EU_WEST_1, + ) + ) + sns_client.provider = mock.MagicMock() + sns_client.provider.organizations_metadata = mock.MagicMock() + sns_client.provider.organizations_metadata.organization_id = org_id + with mock.patch( + "prowler.providers.aws.services.sns.sns_service.SNS", + sns_client, + ): + from prowler.providers.aws.services.sns.sns_topics_not_publicly_accessible.sns_topics_not_publicly_accessible import ( + sns_topics_not_publicly_accessible, + ) + + check = sns_topics_not_publicly_accessible() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SNS topic {topic_name} is public because its policy allows public access." + ) + assert result[0].resource_id == topic_name + assert result[0].resource_arn == topic_arn + assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource_tags == [] From b810d45d34a569d231d5792191e81b57d306fd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Thu, 15 May 2025 16:08:09 +0200 Subject: [PATCH 325/359] feat(findings): Add /findings/latest and /findings/metadata/latest endpoints (#7743) --- api/CHANGELOG.md | 1 + api/src/backend/api/filters.py | 232 ++++--- api/src/backend/api/specs/v1.yaml | 796 ++++++++++++++++++++++++ api/src/backend/api/tests/test_views.py | 23 + api/src/backend/api/v1/mixins.py | 33 + api/src/backend/api/v1/views.py | 151 ++++- api/src/backend/conftest.py | 41 ++ 7 files changed, 1162 insertions(+), 115 deletions(-) create mode 100644 api/src/backend/api/v1/mixins.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index f25354e058..7ecf828e69 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler API** are documented in this file. - Added huge improvements to `/findings/metadata` and resource related filters for findings [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690). - Added improvements to `/overviews` endpoints [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690). - Added new queue to perform backfill background tasks [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690). +- Added new endpoints to retrieve latest findings and metadata [(#7743)](https://github.com/prowler-cloud/prowler/pull/7743). --- diff --git a/api/src/backend/api/filters.py b/api/src/backend/api/filters.py index 6d9512f2e2..9e95016e1d 100644 --- a/api/src/backend/api/filters.py +++ b/api/src/backend/api/filters.py @@ -81,6 +81,114 @@ class ChoiceInFilter(BaseInFilter, ChoiceFilter): pass +class CommonFindingFilters(FilterSet): + # We filter providers from the scan in findings + provider = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact") + provider__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in") + provider_type = ChoiceFilter( + choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider" + ) + provider_type__in = ChoiceInFilter( + choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider" + ) + provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact") + provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in") + provider_uid__icontains = CharFilter( + field_name="scan__provider__uid", lookup_expr="icontains" + ) + provider_alias = CharFilter(field_name="scan__provider__alias", lookup_expr="exact") + provider_alias__in = CharInFilter( + field_name="scan__provider__alias", lookup_expr="in" + ) + provider_alias__icontains = CharFilter( + field_name="scan__provider__alias", lookup_expr="icontains" + ) + + updated_at = DateFilter(field_name="updated_at", lookup_expr="date") + + uid = CharFilter(field_name="uid") + delta = ChoiceFilter(choices=Finding.DeltaChoices.choices) + status = ChoiceFilter(choices=StatusChoices.choices) + severity = ChoiceFilter(choices=SeverityChoices) + impact = ChoiceFilter(choices=SeverityChoices) + muted = BooleanFilter( + help_text="If this filter is not provided, muted and non-muted findings will be returned." + ) + + resources = UUIDInFilter(field_name="resource__id", lookup_expr="in") + + region = CharFilter(method="filter_resource_region") + region__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap") + region__icontains = CharFilter( + field_name="resource_regions", lookup_expr="icontains" + ) + + service = CharFilter(method="filter_resource_service") + service__in = CharInFilter(field_name="resource_services", lookup_expr="overlap") + service__icontains = CharFilter( + field_name="resource_services", lookup_expr="icontains" + ) + + resource_uid = CharFilter(field_name="resources__uid") + resource_uid__in = CharInFilter(field_name="resources__uid", lookup_expr="in") + resource_uid__icontains = CharFilter( + field_name="resources__uid", lookup_expr="icontains" + ) + + resource_name = CharFilter(field_name="resources__name") + resource_name__in = CharInFilter(field_name="resources__name", lookup_expr="in") + resource_name__icontains = CharFilter( + field_name="resources__name", lookup_expr="icontains" + ) + + resource_type = CharFilter(method="filter_resource_type") + resource_type__in = CharInFilter(field_name="resource_types", lookup_expr="overlap") + resource_type__icontains = CharFilter( + field_name="resources__type", lookup_expr="icontains" + ) + + # Temporarily disabled until we implement tag filtering in the UI + # resource_tag_key = CharFilter(field_name="resources__tags__key") + # resource_tag_key__in = CharInFilter( + # field_name="resources__tags__key", lookup_expr="in" + # ) + # resource_tag_key__icontains = CharFilter( + # field_name="resources__tags__key", lookup_expr="icontains" + # ) + # resource_tag_value = CharFilter(field_name="resources__tags__value") + # resource_tag_value__in = CharInFilter( + # field_name="resources__tags__value", lookup_expr="in" + # ) + # resource_tag_value__icontains = CharFilter( + # field_name="resources__tags__value", lookup_expr="icontains" + # ) + # resource_tags = CharInFilter( + # method="filter_resource_tag", + # lookup_expr="in", + # help_text="Filter by resource tags `key:value` pairs.\nMultiple values may be " + # "separated by commas.", + # ) + + def filter_resource_service(self, queryset, name, value): + return queryset.filter(resource_services__contains=[value]) + + def filter_resource_region(self, queryset, name, value): + return queryset.filter(resource_regions__contains=[value]) + + def filter_resource_type(self, queryset, name, value): + return queryset.filter(resource_types__contains=[value]) + + def filter_resource_tag(self, queryset, name, value): + overall_query = Q() + for key_value_pair in value: + tag_key, tag_value = key_value_pair.split(":", 1) + overall_query |= Q( + resources__tags__key__icontains=tag_key, + resources__tags__value__icontains=tag_value, + ) + return queryset.filter(overall_query).distinct() + + class TenantFilter(FilterSet): inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date") updated_at = DateFilter(field_name="updated_at", lookup_expr="date") @@ -257,94 +365,7 @@ class ResourceFilter(ProviderRelationshipFilterSet): return queryset.filter(tags__text_search=value) -class FindingFilter(FilterSet): - # We filter providers from the scan in findings - provider = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact") - provider__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in") - provider_type = ChoiceFilter( - choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider" - ) - provider_type__in = ChoiceInFilter( - choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider" - ) - provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact") - provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in") - provider_uid__icontains = CharFilter( - field_name="scan__provider__uid", lookup_expr="icontains" - ) - provider_alias = CharFilter(field_name="scan__provider__alias", lookup_expr="exact") - provider_alias__in = CharInFilter( - field_name="scan__provider__alias", lookup_expr="in" - ) - provider_alias__icontains = CharFilter( - field_name="scan__provider__alias", lookup_expr="icontains" - ) - - updated_at = DateFilter(field_name="updated_at", lookup_expr="date") - - uid = CharFilter(field_name="uid") - delta = ChoiceFilter(choices=Finding.DeltaChoices.choices) - status = ChoiceFilter(choices=StatusChoices.choices) - severity = ChoiceFilter(choices=SeverityChoices) - impact = ChoiceFilter(choices=SeverityChoices) - muted = BooleanFilter( - help_text="If this filter is not provided, muted and non-muted findings will be returned." - ) - - resources = UUIDInFilter(field_name="resource__id", lookup_expr="in") - - region = CharFilter(method="filter_resource_region") - region__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap") - region__icontains = CharFilter( - field_name="resource_regions", lookup_expr="icontains" - ) - - service = CharFilter(method="filter_resource_service") - service__in = CharInFilter(field_name="resource_services", lookup_expr="overlap") - service__icontains = CharFilter( - field_name="resource_services", lookup_expr="icontains" - ) - - resource_uid = CharFilter(field_name="resources__uid") - resource_uid__in = CharInFilter(field_name="resources__uid", lookup_expr="in") - resource_uid__icontains = CharFilter( - field_name="resources__uid", lookup_expr="icontains" - ) - - resource_name = CharFilter(field_name="resources__name") - resource_name__in = CharInFilter(field_name="resources__name", lookup_expr="in") - resource_name__icontains = CharFilter( - field_name="resources__name", lookup_expr="icontains" - ) - - resource_type = CharFilter(method="filter_resource_type") - resource_type__in = CharInFilter(field_name="resource_types", lookup_expr="overlap") - resource_type__icontains = CharFilter( - field_name="resources__type", lookup_expr="icontains" - ) - - # Temporarily disabled until we implement tag filtering in the UI - # resource_tag_key = CharFilter(field_name="resources__tags__key") - # resource_tag_key__in = CharInFilter( - # field_name="resources__tags__key", lookup_expr="in" - # ) - # resource_tag_key__icontains = CharFilter( - # field_name="resources__tags__key", lookup_expr="icontains" - # ) - # resource_tag_value = CharFilter(field_name="resources__tags__value") - # resource_tag_value__in = CharInFilter( - # field_name="resources__tags__value", lookup_expr="in" - # ) - # resource_tag_value__icontains = CharFilter( - # field_name="resources__tags__value", lookup_expr="icontains" - # ) - # resource_tags = CharInFilter( - # method="filter_resource_tag", - # lookup_expr="in", - # help_text="Filter by resource tags `key:value` pairs.\nMultiple values may be " - # "separated by commas.", - # ) - +class FindingFilter(CommonFindingFilters): scan = UUIDFilter(method="filter_scan_id") scan__in = UUIDInFilter(method="filter_scan_id_in") @@ -512,16 +533,6 @@ class FindingFilter(FilterSet): return queryset.filter(id__lt=end) - def filter_resource_tag(self, queryset, name, value): - overall_query = Q() - for key_value_pair in value: - tag_key, tag_value = key_value_pair.split(":", 1) - overall_query |= Q( - resources__tags__key__icontains=tag_key, - resources__tags__value__icontains=tag_value, - ) - return queryset.filter(overall_query).distinct() - @staticmethod def maybe_date_to_datetime(value): dt = value @@ -530,6 +541,31 @@ class FindingFilter(FilterSet): return dt +class LatestFindingFilter(CommonFindingFilters): + class Meta: + model = Finding + fields = { + "id": ["exact", "in"], + "uid": ["exact", "in"], + "delta": ["exact", "in"], + "status": ["exact", "in"], + "severity": ["exact", "in"], + "impact": ["exact", "in"], + "check_id": ["exact", "in", "icontains"], + } + filter_overrides = { + FindingDeltaEnumField: { + "filter_class": CharFilter, + }, + StatusEnumField: { + "filter_class": CharFilter, + }, + SeverityEnumField: { + "filter_class": CharFilter, + }, + } + + class ProviderSecretFilter(FilterSet): inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date") updated_at = DateFilter(field_name="updated_at", lookup_expr="date") diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 534a232ca8..4a5bdb4662 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1238,6 +1238,416 @@ paths: schema: $ref: '#/components/schemas/FindingDynamicFilterResponse' description: '' + /api/v1/findings/latest: + get: + operationId: findings_latest_retrieve + description: Retrieve a list of the latest findings from the latest scans for + each provider with options for filtering by various criteria. + summary: List the latest findings + parameters: + - in: query + name: fields[findings] + schema: + type: array + items: + type: string + enum: + - uid + - delta + - status + - status_extended + - severity + - check_id + - check_metadata + - raw_result + - inserted_at + - updated_at + - first_seen_at + - muted + - url + - scan + - resources + description: endpoint return only specific fields in the response on a per-type + basis by including a fields[TYPE] query parameter. + explode: false + - in: query + name: filter[check_id] + schema: + type: string + - in: query + name: filter[check_id__icontains] + schema: + type: string + - in: query + name: filter[check_id__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[delta] + schema: + type: string + nullable: true + enum: + - changed + - new + description: |- + * `new` - New + * `changed` - Changed + - in: query + name: filter[delta__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[id] + schema: + type: string + format: uuid + - in: query + name: filter[id__in] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[impact] + schema: + type: string + enum: + - critical + - high + - informational + - low + - medium + description: |- + * `critical` - Critical + * `high` - High + * `medium` - Medium + * `low` - Low + * `informational` - Informational + - in: query + name: filter[impact__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[muted] + schema: + type: boolean + description: If this filter is not provided, muted and non-muted findings + will be returned. + - in: query + name: filter[provider] + schema: + type: string + format: uuid + - in: query + name: filter[provider__in] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[provider_alias] + schema: + type: string + - in: query + name: filter[provider_alias__icontains] + schema: + type: string + - in: query + name: filter[provider_alias__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[provider_type] + schema: + type: string + enum: + - aws + - azure + - gcp + - kubernetes + - m365 + description: |- + * `aws` - AWS + * `azure` - Azure + * `gcp` - GCP + * `kubernetes` - Kubernetes + * `m365` - M365 + - in: query + name: filter[provider_type__in] + schema: + type: array + items: + type: string + enum: + - aws + - azure + - gcp + - kubernetes + - m365 + description: |- + Multiple values may be separated by commas. + + * `aws` - AWS + * `azure` - Azure + * `gcp` - GCP + * `kubernetes` - Kubernetes + * `m365` - M365 + explode: false + style: form + - in: query + name: filter[provider_uid] + schema: + type: string + - in: query + name: filter[provider_uid__icontains] + schema: + type: string + - in: query + name: filter[provider_uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[region] + schema: + type: string + - in: query + name: filter[region__icontains] + schema: + type: string + - in: query + name: filter[region__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_name] + schema: + type: string + - in: query + name: filter[resource_name__icontains] + schema: + type: string + - in: query + name: filter[resource_name__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_type] + schema: + type: string + - in: query + name: filter[resource_type__icontains] + schema: + type: string + - in: query + name: filter[resource_type__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_uid] + schema: + type: string + - in: query + name: filter[resource_uid__icontains] + schema: + type: string + - in: query + name: filter[resource_uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resources] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - name: filter[search] + required: false + in: query + description: A search term. + schema: + type: string + - in: query + name: filter[service] + schema: + type: string + - in: query + name: filter[service__icontains] + schema: + type: string + - in: query + name: filter[service__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[severity] + schema: + type: string + enum: + - critical + - high + - informational + - low + - medium + description: |- + * `critical` - Critical + * `high` - High + * `medium` - Medium + * `low` - Low + * `informational` - Informational + - in: query + name: filter[severity__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[status] + schema: + type: string + enum: + - FAIL + - MANUAL + - PASS + description: |- + * `FAIL` - Fail + * `PASS` - Pass + * `MANUAL` - Manual + - in: query + name: filter[status__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[uid] + schema: + type: string + - in: query + name: filter[uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[updated_at] + schema: + type: string + format: date + - in: query + name: include + schema: + type: array + items: + type: string + enum: + - scan + - resources + description: include query parameter to allow the client to customize which + related resources should be returned. + explode: false + - name: sort + required: false + in: query + description: '[list of fields to sort by](https://jsonapi.org/format/#fetching-sorting)' + schema: + type: array + items: + type: string + enum: + - status + - -status + - severity + - -severity + - check_id + - -check_id + - inserted_at + - -inserted_at + - updated_at + - -updated_at + explode: false + tags: + - Finding + security: + - jwtAuth: [] + responses: + '200': + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FindingResponse' + description: '' /api/v1/findings/metadata: get: operationId: findings_metadata_retrieve @@ -1674,6 +2084,392 @@ paths: schema: $ref: '#/components/schemas/FindingMetadataResponse' description: '' + /api/v1/findings/metadata/latest: + get: + operationId: findings_metadata_latest_retrieve + description: Fetch unique metadata values from a set of findings from the latest + scans for each provider. This is useful for dynamic filtering. + summary: Retrieve metadata values from the latest findings + parameters: + - in: query + name: fields[findings-metadata] + schema: + type: array + items: + type: string + enum: + - services + - regions + - resource_types + description: endpoint return only specific fields in the response on a per-type + basis by including a fields[TYPE] query parameter. + explode: false + - in: query + name: filter[check_id] + schema: + type: string + - in: query + name: filter[check_id__icontains] + schema: + type: string + - in: query + name: filter[check_id__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[delta] + schema: + type: string + nullable: true + enum: + - changed + - new + description: |- + * `new` - New + * `changed` - Changed + - in: query + name: filter[delta__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[id] + schema: + type: string + format: uuid + - in: query + name: filter[id__in] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[impact] + schema: + type: string + enum: + - critical + - high + - informational + - low + - medium + description: |- + * `critical` - Critical + * `high` - High + * `medium` - Medium + * `low` - Low + * `informational` - Informational + - in: query + name: filter[impact__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[muted] + schema: + type: boolean + description: If this filter is not provided, muted and non-muted findings + will be returned. + - in: query + name: filter[provider] + schema: + type: string + format: uuid + - in: query + name: filter[provider__in] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[provider_alias] + schema: + type: string + - in: query + name: filter[provider_alias__icontains] + schema: + type: string + - in: query + name: filter[provider_alias__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[provider_type] + schema: + type: string + enum: + - aws + - azure + - gcp + - kubernetes + - m365 + description: |- + * `aws` - AWS + * `azure` - Azure + * `gcp` - GCP + * `kubernetes` - Kubernetes + * `m365` - M365 + - in: query + name: filter[provider_type__in] + schema: + type: array + items: + type: string + enum: + - aws + - azure + - gcp + - kubernetes + - m365 + description: |- + Multiple values may be separated by commas. + + * `aws` - AWS + * `azure` - Azure + * `gcp` - GCP + * `kubernetes` - Kubernetes + * `m365` - M365 + explode: false + style: form + - in: query + name: filter[provider_uid] + schema: + type: string + - in: query + name: filter[provider_uid__icontains] + schema: + type: string + - in: query + name: filter[provider_uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[region] + schema: + type: string + - in: query + name: filter[region__icontains] + schema: + type: string + - in: query + name: filter[region__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_name] + schema: + type: string + - in: query + name: filter[resource_name__icontains] + schema: + type: string + - in: query + name: filter[resource_name__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_type] + schema: + type: string + - in: query + name: filter[resource_type__icontains] + schema: + type: string + - in: query + name: filter[resource_type__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resource_uid] + schema: + type: string + - in: query + name: filter[resource_uid__icontains] + schema: + type: string + - in: query + name: filter[resource_uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[resources] + schema: + type: array + items: + type: string + format: uuid + description: Multiple values may be separated by commas. + explode: false + style: form + - name: filter[search] + required: false + in: query + description: A search term. + schema: + type: string + - in: query + name: filter[service] + schema: + type: string + - in: query + name: filter[service__icontains] + schema: + type: string + - in: query + name: filter[service__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[severity] + schema: + type: string + enum: + - critical + - high + - informational + - low + - medium + description: |- + * `critical` - Critical + * `high` - High + * `medium` - Medium + * `low` - Low + * `informational` - Informational + - in: query + name: filter[severity__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[status] + schema: + type: string + enum: + - FAIL + - MANUAL + - PASS + description: |- + * `FAIL` - Fail + * `PASS` - Pass + * `MANUAL` - Manual + - in: query + name: filter[status__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[uid] + schema: + type: string + - in: query + name: filter[uid__in] + schema: + type: array + items: + type: string + description: Multiple values may be separated by commas. + explode: false + style: form + - in: query + name: filter[updated_at] + schema: + type: string + format: date + - name: sort + required: false + in: query + description: '[list of fields to sort by](https://jsonapi.org/format/#fetching-sorting)' + schema: + type: array + items: + type: string + enum: + - status + - -status + - severity + - -severity + - check_id + - -check_id + - inserted_at + - -inserted_at + - updated_at + - -updated_at + explode: false + tags: + - Finding + security: + - jwtAuth: [] + responses: + '200': + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FindingMetadataResponse' + description: '' /api/v1/integrations: get: operationId: integrations_list diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 0608c4a378..a82348fe87 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -3185,6 +3185,29 @@ class TestFindingViewSet: ] } + def test_findings_latest(self, authenticated_client, latest_scan_finding): + response = authenticated_client.get( + reverse("finding-latest"), + ) + assert response.status_code == status.HTTP_200_OK + # The latest scan only has one finding, in comparison with `GET /findings` + assert len(response.json()["data"]) == 1 + assert ( + response.json()["data"][0]["attributes"]["status"] + == latest_scan_finding.status + ) + + def test_findings_metadata_latest(self, authenticated_client, latest_scan_finding): + response = authenticated_client.get( + reverse("finding-metadata_latest"), + ) + assert response.status_code == status.HTTP_200_OK + attributes = response.json()["data"]["attributes"] + + assert attributes["services"] == latest_scan_finding.resource_services + assert attributes["regions"] == latest_scan_finding.resource_regions + assert attributes["resource_types"] == latest_scan_finding.resource_types + @pytest.mark.django_db class TestJWTFields: diff --git a/api/src/backend/api/v1/mixins.py b/api/src/backend/api/v1/mixins.py new file mode 100644 index 0000000000..85250c0eef --- /dev/null +++ b/api/src/backend/api/v1/mixins.py @@ -0,0 +1,33 @@ +from rest_framework.response import Response + + +class PaginateByPkMixin: + """ + Mixin to paginate on a list of PKs (cheaper than heavy JOINs), + re-fetch the full objects with the desired select/prefetch, + re-sort them to preserve DB ordering, then serialize + return. + """ + + def paginate_by_pk( + self, + request, # noqa: F841 + base_queryset, + manager, + select_related: list[str] | None = None, + prefetch_related: list[str] | None = None, + ) -> Response: + pk_list = base_queryset.values_list("id", flat=True) + page = self.paginate_queryset(pk_list) + if page is None: + return Response(self.get_serializer(base_queryset, many=True).data) + + queryset = manager.filter(id__in=page) + if select_related: + queryset = queryset.select_related(*select_related) + if prefetch_related: + queryset = queryset.prefetch_related(*prefetch_related) + + queryset = sorted(queryset, key=lambda obj: page.index(obj.id)) + + serialized = self.get_serializer(queryset, many=True).data + return self.get_paginated_response(serialized) diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index ded955c93a..eec7b4827c 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -65,6 +65,7 @@ from api.filters import ( FindingFilter, IntegrationFilter, InvitationFilter, + LatestFindingFilter, MembershipFilter, ProviderFilter, ProviderGroupFilter, @@ -110,6 +111,7 @@ from api.utils import ( validate_invitation, ) from api.uuid_utils import datetime_to_uuid7, uuid7_start +from api.v1.mixins import PaginateByPkMixin from api.v1.serializers import ( ComplianceOverviewFullSerializer, ComplianceOverviewMetadataSerializer, @@ -1671,10 +1673,24 @@ class ResourceViewSet(BaseRLSViewSet): ], filters=True, ), + latest=extend_schema( + tags=["Finding"], + summary="List the latest findings", + description="Retrieve a list of the latest findings from the latest scans for each provider with options for " + "filtering by various criteria.", + filters=True, + ), + metadata_latest=extend_schema( + tags=["Finding"], + summary="Retrieve metadata values from the latest findings", + description="Fetch unique metadata values from a set of findings from the latest scans for each provider. " + "This is useful for dynamic filtering.", + filters=True, + ), ) @method_decorator(CACHE_DECORATOR, name="list") @method_decorator(CACHE_DECORATOR, name="retrieve") -class FindingViewSet(BaseRLSViewSet): +class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): queryset = Finding.all_objects.all() serializer_class = FindingSerializer filterset_class = FindingFilter @@ -1706,11 +1722,16 @@ class FindingViewSet(BaseRLSViewSet): def get_serializer_class(self): if self.action == "findings_services_regions": return FindingDynamicFilterSerializer - elif self.action == "metadata": + elif self.action in ["metadata", "metadata_latest"]: return FindingMetadataSerializer return super().get_serializer_class() + def get_filterset_class(self): + if self.action in ["latest", "metadata_latest"]: + return LatestFindingFilter + return FindingFilter + def get_queryset(self): tenant_id = self.request.tenant_id user_roles = get_role(self.request.user) @@ -1750,21 +1771,14 @@ class FindingViewSet(BaseRLSViewSet): return super().filter_queryset(queryset) def list(self, request, *args, **kwargs): - base_qs = self.filter_queryset(self.get_queryset()) - paginated_ids = self.paginate_queryset(base_qs.values_list("id", flat=True)) - if paginated_ids is not None: - ids = list(paginated_ids) - findings = ( - Finding.all_objects.filter(tenant_id=self.request.tenant_id, id__in=ids) - .select_related("scan") - .prefetch_related("resources") - ) - # Re-sort in Python to preserve ordering: - findings = sorted(findings, key=lambda x: ids.index(x.id)) - serializer = self.get_serializer(findings, many=True) - return self.get_paginated_response(serializer.data) - serializer = self.get_serializer(base_qs, many=True) - return Response(serializer.data) + filtered_queryset = self.filter_queryset(self.get_queryset()) + return self.paginate_by_pk( + request, + filtered_queryset, + manager=Finding.all_objects, + select_related=["scan"], + prefetch_related=["resources"], + ) @action(detail=False, methods=["get"], url_name="findings_services_regions") def findings_services_regions(self, request): @@ -1897,6 +1911,109 @@ class FindingViewSet(BaseRLSViewSet): serializer.is_valid(raise_exception=True) return Response(serializer.data) + @action(detail=False, methods=["get"], url_name="latest") + def latest(self, request): + tenant_id = request.tenant_id + filtered_queryset = self.filter_queryset(self.get_queryset()) + + latest_scan_ids = ( + Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED) + .order_by("provider_id", "-inserted_at") + .distinct("provider_id") + .values_list("id", flat=True) + ) + filtered_queryset = filtered_queryset.filter( + tenant_id=tenant_id, scan_id__in=latest_scan_ids + ) + + return self.paginate_by_pk( + request, + filtered_queryset, + manager=Finding.all_objects, + select_related=["scan"], + prefetch_related=["resources"], + ) + + @action( + detail=False, + methods=["get"], + url_name="metadata_latest", + url_path="metadata/latest", + ) + def metadata_latest(self, request): + # Force filter validation + filtered_queryset = self.filter_queryset(self.get_queryset()) + + tenant_id = request.tenant_id + query_params = request.query_params + + latest_scan_ids = ( + Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED) + .order_by("provider_id", "-inserted_at") + .distinct("provider_id") + .values_list("id", flat=True) + ) + + queryset = ResourceScanSummary.objects.filter( + tenant_id=tenant_id, scan_id__in=latest_scan_ids + ) + # ToRemove: Temporary fallback mechanism + scans_with_flag = latest_scan_ids.annotate( + has_summary=Exists( + ResourceScanSummary.objects.filter( + tenant_id=tenant_id, + scan_id=OuterRef("pk"), + ) + ) + ) + if missing_scan_ids := scans_with_flag.filter(has_summary=False).values_list( + "id", flat=True + ): + for scan_id in missing_scan_ids: + backfill_scan_resource_summaries_task.apply_async( + kwargs={"tenant_id": tenant_id, "scan_id": scan_id} + ) + return Response( + get_findings_metadata_no_aggregations(tenant_id, filtered_queryset) + ) + + if service_filter := query_params.get("filter[service]") or query_params.get( + "filter[service__in]" + ): + queryset = queryset.filter(service__in=service_filter.split(",")) + if region_filter := query_params.get("filter[region]") or query_params.get( + "filter[region__in]" + ): + queryset = queryset.filter(region__in=region_filter.split(",")) + if resource_type_filter := query_params.get( + "filter[resource_type]" + ) or query_params.get("filter[resource_type__in]"): + queryset = queryset.filter( + resource_type__in=resource_type_filter.split(",") + ) + + services = list( + queryset.values_list("service", flat=True).distinct().order_by("service") + ) + regions = list( + queryset.values_list("region", flat=True).distinct().order_by("region") + ) + resource_types = list( + queryset.values_list("resource_type", flat=True) + .distinct() + .order_by("resource_type") + ) + + result = { + "services": services, + "regions": regions, + "resource_types": resource_types, + } + + serializer = self.get_serializer(data=result) + serializer.is_valid(raise_exception=True) + return Response(serializer.data) + @extend_schema_view( list=extend_schema( diff --git a/api/src/backend/conftest.py b/api/src/backend/conftest.py index 2fba4cebb7..8f58c447de 100644 --- a/api/src/backend/conftest.py +++ b/api/src/backend/conftest.py @@ -929,6 +929,47 @@ def backfill_scan_metadata_fixture(scans_fixture, findings_fixture): backfill_resource_scan_summaries(tenant_id=tenant_id, scan_id=scan_id) +@pytest.fixture(scope="function") +def latest_scan_finding(authenticated_client, providers_fixture, resources_fixture): + provider = providers_fixture[0] + tenant_id = str(providers_fixture[0].tenant_id) + resource = resources_fixture[0] + scan = Scan.objects.create( + name="latest completed scan", + provider=provider, + trigger=Scan.TriggerChoices.MANUAL, + state=StateChoices.COMPLETED, + tenant_id=tenant_id, + ) + finding = Finding.objects.create( + tenant_id=tenant_id, + uid="test_finding_uid_1", + scan=scan, + delta="new", + status=Status.FAIL, + status_extended="test status extended ", + impact=Severity.critical, + impact_extended="test impact extended one", + severity=Severity.critical, + raw_result={ + "status": Status.FAIL, + "impact": Severity.critical, + "severity": Severity.critical, + }, + tags={"test": "dev-qa"}, + check_id="test_check_id", + check_metadata={ + "CheckId": "test_check_id", + "Description": "test description apple sauce", + }, + first_seen_at="2024-01-02T00:00:00Z", + ) + + finding.add_resources([resource]) + backfill_resource_scan_summaries(tenant_id, str(scan.id)) + return finding + + def get_authorization_header(access_token: str) -> dict: return {"Authorization": f"Bearer {access_token}"} From 6417e6bbba529fd8284f1e3598e09a52acc21acf Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 16 May 2025 08:18:12 +0200 Subject: [PATCH 326/359] feat: use getFindingsLatest when no scan or date filters are applied (#7756) --- ui/CHANGELOG.md | 1 + ui/actions/findings/findings.ts | 83 +++++++++++++++++++++++++++++ ui/app/(prowler)/findings/page.tsx | 85 +++++++++--------------------- ui/lib/helper-filters.ts | 46 ++++++++++++++++ ui/lib/index.ts | 1 + 5 files changed, 155 insertions(+), 61 deletions(-) create mode 100644 ui/lib/helper-filters.ts diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index b6fc46f57b..1e80a6d44b 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Added `Accordion` component. [(#7700)](https://github.com/prowler-cloud/prowler/pull/7700) - Improve `Provider UID` filter by adding more context and enhancing the UI/UX. [(#7741)](https://github.com/prowler-cloud/prowler/pull/7741) - Added an AWS CloudFormation Quick Link to the IAM Role credentials step [(#7735)](https://github.com/prowler-cloud/prowler/pull/7735) +– Use `getLatestFindings` on findings page when no scan or date filters are applied. [(#7756)](https://github.com/prowler-cloud/prowler/pull/7756) ### 🐞 Fixes diff --git a/ui/actions/findings/findings.ts b/ui/actions/findings/findings.ts index 3d7f1fec37..0f2359a421 100644 --- a/ui/actions/findings/findings.ts +++ b/ui/actions/findings/findings.ts @@ -44,6 +44,47 @@ export const getFindings = async ({ } }; +export const getLatestFindings = async ({ + page = 1, + pageSize = 10, + query = "", + sort = "", + filters = {}, +}) => { + const headers = await getAuthHeaders({ contentType: false }); + + if (isNaN(Number(page)) || page < 1) + redirect("findings?include=resources,scan.provider"); + + const url = new URL( + `${apiBaseUrl}/findings/latest?include=resources,scan.provider`, + ); + + if (page) url.searchParams.append("page[number]", page.toString()); + if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); + + if (query) url.searchParams.append("filter[search]", query); + if (sort) url.searchParams.append("sort", sort); + + Object.entries(filters).forEach(([key, value]) => { + url.searchParams.append(key, String(value)); + }); + + try { + const findings = await fetch(url.toString(), { + headers, + }); + const data = await findings.json(); + const parsedData = parseStringify(data); + revalidatePath("/findings"); + return parsedData; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching findings:", error); + return undefined; + } +}; + export const getMetadataInfo = async ({ query = "", sort = "", @@ -85,3 +126,45 @@ export const getMetadataInfo = async ({ return undefined; } }; + +export const getLatestMetadataInfo = async ({ + query = "", + sort = "", + filters = {}, +}) => { + const headers = await getAuthHeaders({ contentType: false }); + + const url = new URL(`${apiBaseUrl}/findings/metadata/latest`); + + if (query) url.searchParams.append("filter[search]", query); + if (sort) url.searchParams.append("sort", sort); + + Object.entries(filters).forEach(([key, value]) => { + // Define filters to exclude + const excludedFilters = ["region__in", "service__in", "resource_type__in"]; + if ( + key !== "filter[search]" && + !excludedFilters.some((filter) => key.includes(filter)) + ) { + url.searchParams.append(key, String(value)); + } + }); + + try { + const response = await fetch(url.toString(), { + headers, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch metadata info: ${response.statusText}`); + } + + const parsedData = parseStringify(await response.json()); + + return parsedData; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching metadata info:", error); + return undefined; + } +}; diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index a894210fa8..3615c77b3b 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -1,8 +1,12 @@ import { Spacer } from "@nextui-org/react"; -import { format, subDays } from "date-fns"; import React, { Suspense } from "react"; -import { getFindings, getMetadataInfo } from "@/actions/findings"; +import { + getFindings, + getLatestFindings, + getLatestMetadataInfo, + getMetadataInfo, +} from "@/actions/findings"; import { getProviders } from "@/actions/providers"; import { getScans } from "@/actions/scans"; import { filterFindings } from "@/components/filters/data-filters"; @@ -13,7 +17,12 @@ import { } from "@/components/findings/table"; import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; -import { createDict } from "@/lib"; +import { + createDict, + extractFiltersAndQuery, + extractSortAndKey, + hasDateOrScanFilter, +} from "@/lib"; import { ProviderAccountProps, ProviderProps } from "@/types"; import { FindingProps, ScanProps, SearchParamsProps } from "@/types/components"; @@ -22,41 +31,14 @@ export default async function Findings({ }: { searchParams: SearchParamsProps; }) { - const searchParamsKey = JSON.stringify(searchParams || {}); - const sort = searchParams.sort?.toString(); - - // Make sure the sort is correctly encoded - const encodedSort = sort?.replace(/^\+/, ""); - - const twoDaysAgo = format(subDays(new Date(), 2), "yyyy-MM-dd"); + const { searchParamsKey, encodedSort } = extractSortAndKey(searchParams); + const { filters, query } = extractFiltersAndQuery(searchParams); // Check if the searchParams contain any date or scan filter - const hasDateOrScanFilter = Object.keys(searchParams).some( - (key) => key.includes("inserted_at") || key.includes("scan__in"), - ); - - // Default filters for getMetadataInfo - const defaultFilters: Record = hasDateOrScanFilter - ? {} // Do not apply default filters if there are date or scan filters - : { "filter[inserted_at__gte]": twoDaysAgo }; - - // Extract all filter parameters and combine with default filters - const filters: Record = { - ...defaultFilters, - ...Object.fromEntries( - Object.entries(searchParams) - .filter(([key]) => key.startsWith("filter[")) - .map(([key, value]) => [ - key, - Array.isArray(value) ? value.join(",") : value?.toString() || "", - ]), - ), - }; - - const query = filters["filter[search]"] || ""; + const hasDateOrScan = hasDateOrScanFilter(searchParams); const [metadataInfoData, providersData, scansData] = await Promise.all([ - getMetadataInfo({ + (hasDateOrScan ? getMetadataInfo : getLatestMetadataInfo)({ query, sort: encodedSort, filters, @@ -163,38 +145,19 @@ const SSRDataTable = async ({ const page = parseInt(searchParams.page?.toString() || "1", 10); const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); const defaultSort = "severity,status,-inserted_at"; - const sort = searchParams.sort?.toString() || defaultSort; - // Make sure the sort is correctly encoded - const encodedSort = sort.replace(/^\+/, ""); - - const twoDaysAgo = format(subDays(new Date(), 2), "yyyy-MM-dd"); + const { encodedSort } = extractSortAndKey({ + ...searchParams, + sort: searchParams.sort ?? defaultSort, + }); + const { filters, query } = extractFiltersAndQuery(searchParams); // Check if the searchParams contain any date or scan filter - const hasDateOrScanFilter = Object.keys(searchParams).some( - (key) => key.includes("inserted_at") || key.includes("scan__in"), - ); + const hasDateOrScan = hasDateOrScanFilter(searchParams); - // Default filters for getFindings - const defaultFilters: Record = hasDateOrScanFilter - ? {} // Do not apply default filters if there are date or scan filters - : { "filter[inserted_at__gte]": twoDaysAgo }; + const fetchFindings = hasDateOrScan ? getFindings : getLatestFindings; - const filters: Record = { - ...defaultFilters, - ...Object.fromEntries( - Object.entries(searchParams) - .filter(([key]) => key.startsWith("filter[")) - .map(([key, value]) => [ - key, - Array.isArray(value) ? value.join(",") : value?.toString() || "", - ]), - ), - }; - - const query = filters["filter[search]"] || ""; - - const findingsData = await getFindings({ + const findingsData = await fetchFindings({ query, page, sort: encodedSort, diff --git a/ui/lib/helper-filters.ts b/ui/lib/helper-filters.ts new file mode 100644 index 0000000000..fe17185746 --- /dev/null +++ b/ui/lib/helper-filters.ts @@ -0,0 +1,46 @@ +/** + * Extracts normalized filters and search query from the URL search params. + * Used Server Side Rendering (SSR). There is a hook (useUrlFilters) for client side. + */ +export const extractFiltersAndQuery = ( + searchParams: Record, +) => { + const filters: Record = { + ...Object.fromEntries( + Object.entries(searchParams) + .filter(([key]) => key.startsWith("filter[")) + .map(([key, value]) => [ + key, + Array.isArray(value) ? value.join(",") : value?.toString() || "", + ]), + ), + }; + + const query = filters["filter[search]"] || ""; + return { filters, query }; +}; + +/** + * Returns true if there are any scan or inserted_at filters in the search params. + * Used to determine whether to call the full findings endpoint. + */ +export const hasDateOrScanFilter = (searchParams: Record) => + Object.keys(searchParams).some( + (key) => key.includes("inserted_at") || key.includes("scan__in"), + ); + +/** + * Encodes sort strings by removing leading "+" symbols. + */ +export const encodeSort = (sort?: string) => sort?.replace(/^\+/, "") || ""; + +/** + * Extracts the sort string and the stable key to use in Suspense boundaries. + */ +export const extractSortAndKey = (searchParams: Record) => { + const searchParamsKey = JSON.stringify(searchParams || {}); + const rawSort = searchParams.sort?.toString(); + const encodedSort = encodeSort(rawSort); + + return { searchParamsKey, rawSort, encodedSort }; +}; diff --git a/ui/lib/index.ts b/ui/lib/index.ts index 6e1761c9d6..6e17065079 100644 --- a/ui/lib/index.ts +++ b/ui/lib/index.ts @@ -1,4 +1,5 @@ export * from "./external-urls"; export * from "./helper"; +export * from "./helper-filters"; export * from "./menu-list"; export * from "./utils"; From cdc4b362a4b97e745c3451b78a78e591a9032427 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 16 May 2025 08:29:45 +0200 Subject: [PATCH 327/359] feat(repository): add new check `repository_default_branch_protection_applies_to_admins` (#6205) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...protection_applies_to_admins.metadata.json | 30 +++++ ...ult_branch_protection_applies_to_admins.py | 38 ++++++ .../services/repository/repository_service.py | 5 + ...ranch_protection_applies_to_admins_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 7 files changed, 186 insertions(+) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index c3cd28355a..2e00f9ce1a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_disallows_force_push` check for GitHub provider. [(#6197)](https://github.com/prowler-cloud/prowler/pull/6197) - Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200) - Add `repository_default_branch_status_checks_required` check for GitHub provider. [(#6204)](https://github.com/prowler-cloud/prowler/pull/6204) +- Add `repository_default_branch_protection_applies_to_admins` check for GitHub provider. [(#6205)](https://github.com/prowler-cloud/prowler/pull/6205) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.metadata.json new file mode 100644 index 0000000000..a20ff5f930 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_protection_applies_to_admins", + "CheckTitle": "Check if repository enforces admin branch protection", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "GithubRepository", + "Description": "Ensure that the repository enforces branch protection rules for administrators.", + "Risk": "Excluding administrators from branch protection rules introduces a significant risk of unauthorized or unreviewed changes being pushed to protected branches. This can lead to vulnerabilities, including the potential insertion of malicious code, especially if an administrator account is compromised.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#do-not-allow-bypassing-the-above-settings", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enforce branch protection rules for administrators to ensure they adhere to the same security and quality standards as other users. This mitigates the risk of unreviewed or untrusted code being introduced, enhancing the overall integrity of the codebase.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.py b/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.py new file mode 100644 index 0000000000..916ddd35c5 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins.py @@ -0,0 +1,38 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_protection_applies_to_admins(Check): + """Check if a repository enforces administrators to be subject to the same branch protection rules as other users + + This class verifies whether each repository enforces administrators to be subject to the same branch protection rules as other users. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Enforces Admin Branch Protection check + + Iterates over all repositories and checks if they enforce administrators to be subject to the same branch protection rules as other users. + + Returns: + List[CheckReportGithub]: A list of reports for each repository. + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.enforce_admins is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = f"Repository {repo.name} does not enforce administrators to be subject to the same branch protection rules as other users." + + if repo.enforce_admins: + report.status = "PASS" + report.status_extended = f"Repository {repo.name} does enforce administrators to be subject to the same branch protection rules as other users." + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index c9a62f8086..3adcc8a968 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -37,6 +37,7 @@ class Repository(GithubService): allow_force_pushes = True branch_deletion = True status_checks = False + enforce_admins = False try: branch = repo.get_branch(default_branch) if branch.protected: @@ -58,6 +59,7 @@ class Repository(GithubService): status_checks = ( protection.required_status_checks is not None ) + enforce_admins = protection.enforce_admins branch_protection = True except Exception as error: # If the branch is not found, it is not protected @@ -74,6 +76,7 @@ class Repository(GithubService): allow_force_pushes = None branch_deletion = None status_checks = None + enforce_admins = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -91,6 +94,7 @@ class Repository(GithubService): allow_force_pushes=allow_force_pushes, default_branch_deletion=branch_deletion, status_checks=status_checks, + enforce_admins=enforce_admins, default_branch_protection=branch_protection, ) @@ -116,4 +120,5 @@ class Repo(BaseModel): allow_force_pushes: Optional[bool] default_branch_deletion: Optional[bool] status_checks: Optional[bool] + enforce_admins: Optional[bool] approval_count: Optional[int] diff --git a/tests/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins_test.py b/tests/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins_test.py new file mode 100644 index 0000000000..f85bbdced9 --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_protection_applies_to_admins/repository_default_branch_protection_applies_to_admins_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_protection_applies_to_admins_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import ( + repository_default_branch_protection_applies_to_admins, + ) + + check = repository_default_branch_protection_applies_to_admins() + result = check.execute() + assert len(result) == 0 + + def test_enforce_status_checks_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + private=False, + securitymd=False, + enforce_admins=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import ( + repository_default_branch_protection_applies_to_admins, + ) + + check = repository_default_branch_protection_applies_to_admins() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not enforce administrators to be subject to the same branch protection rules as other users." + ) + + def test_enforce_status_checks_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + enforce_admins=True, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import ( + repository_default_branch_protection_applies_to_admins, + ) + + check = repository_default_branch_protection_applies_to_admins() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does enforce administrators to be subject to the same branch protection rules as other users." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index 54aec2936b..a24c1625a7 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -23,6 +23,7 @@ def mock_list_repositories(_): default_branch_deletion=True, status_checks=True, approval_count=2, + enforce_admins=True, ), } @@ -53,4 +54,5 @@ class Test_Repository_Service: assert repository_service.repositories[1].allow_force_pushes assert repository_service.repositories[1].default_branch_deletion assert repository_service.repositories[1].status_checks + assert repository_service.repositories[1].enforce_admins assert repository_service.repositories[1].approval_count == 2 From 7d69cc4cd9246e6347184f065a0a442f0fd35094 Mon Sep 17 00:00:00 2001 From: sumit-tft <70506234+sumit-tft@users.noreply.github.com> Date: Fri, 16 May 2025 12:23:34 +0530 Subject: [PATCH 328/359] fix: Updated the high risk section provider icons to make it consistent (#7706) --- ui/components/icons/Icons.tsx | 55 ++++++++++++++++++++++++++++++----- ui/lib/menu-list.ts | 4 +-- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/ui/components/icons/Icons.tsx b/ui/components/icons/Icons.tsx index 2561fd1cf1..0cb893040f 100644 --- a/ui/components/icons/Icons.tsx +++ b/ui/components/icons/Icons.tsx @@ -995,13 +995,17 @@ export const AzureIcon: React.FC = ({ return ( - + ); }; @@ -1010,6 +1014,7 @@ export const M365Icon: React.FC = ({ size = 24, width, height, + strokeWidth = 2, ...props }) => { return ( @@ -1017,16 +1022,27 @@ export const M365Icon: React.FC = ({ xmlns="http://www.w3.org/2000/svg" width={size || width} height={size || height} - viewBox="0 0 24 24" + viewBox="0 0 48 48" fill="none" stroke="currentColor" - strokeWidth="2" strokeLinecap="round" - strokeLinejoin="round" {...props} > - - + + + ); }; @@ -1046,7 +1062,7 @@ export const GCPIcon: React.FC = ({ fill="currentColor" {...props} > - + ); }; @@ -1078,3 +1094,26 @@ export const MutedIcon: React.FC = ({ ); }; + +export const KubernetesIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + ); +}; diff --git a/ui/lib/menu-list.ts b/ui/lib/menu-list.ts index ce7de725ab..a6c02d6a3a 100644 --- a/ui/lib/menu-list.ts +++ b/ui/lib/menu-list.ts @@ -3,7 +3,6 @@ import { AlertCircle, Bookmark, - Boxes, CloudCog, Group, LayoutGrid, @@ -26,6 +25,7 @@ import { CircleHelpIcon, DocIcon, GCPIcon, + KubernetesIcon, M365Icon, SupportIcon, } from "@/components/icons/Icons"; @@ -108,7 +108,7 @@ export const getMenuList = (pathname: string): GroupProps[] => { { href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=kubernetes&sort=severity,-inserted_at", label: "Kubernetes", - icon: Boxes, + icon: KubernetesIcon, }, ], defaultOpen: false, From 355abca5a37d44bb9ac7900296105c386a29c91e Mon Sep 17 00:00:00 2001 From: sumit-tft <70506234+sumit-tft@users.noreply.github.com> Date: Fri, 16 May 2025 12:32:47 +0530 Subject: [PATCH 329/359] fix(ui): Removed the alias if not available in findings detail page (#7751) --- ui/CHANGELOG.md | 1 + ui/components/findings/table/finding-detail.tsx | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 1e80a6d44b..91dd269fd4 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to the **Prowler UI** are documented in this file. - Fix form validation in launch scan workflow. [(#7693)](https://github.com/prowler-cloud/prowler/pull/7693) - Moved ProviderType to a shared types file and replaced all occurrences across the codebase. [(#7710)](https://github.com/prowler-cloud/prowler/pull/7710) - Added filter to retrieve only connected providers on the scan page. [(#7723)](https://github.com/prowler-cloud/prowler/pull/7723) +- Removed the alias if not added from findings detail page. [(#7751)](https://github.com/prowler-cloud/prowler/pull/7751) --- diff --git a/ui/components/findings/table/finding-detail.tsx b/ui/components/findings/table/finding-detail.tsx index e58040a374..facd6a1d9f 100644 --- a/ui/components/findings/table/finding-detail.tsx +++ b/ui/components/findings/table/finding-detail.tsx @@ -307,7 +307,9 @@ export const FindingDetail = ({
    - {provider.alias} + {provider.alias && ( + {provider.alias} + )} Date: Fri, 16 May 2025 12:41:12 +0200 Subject: [PATCH 330/359] fix(findings): Fix latest metadata backfill condition (#7762) --- api/src/backend/api/v1/views.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index eec7b4827c..36fa3f08f9 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -1947,18 +1947,18 @@ class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): tenant_id = request.tenant_id query_params = request.query_params - latest_scan_ids = ( + latest_scan_queryset = ( Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED) .order_by("provider_id", "-inserted_at") .distinct("provider_id") - .values_list("id", flat=True) ) queryset = ResourceScanSummary.objects.filter( - tenant_id=tenant_id, scan_id__in=latest_scan_ids + tenant_id=tenant_id, + scan_id__in=latest_scan_queryset.values_list("id", flat=True), ) # ToRemove: Temporary fallback mechanism - scans_with_flag = latest_scan_ids.annotate( + scans_with_flag = latest_scan_queryset.annotate( has_summary=Exists( ResourceScanSummary.objects.filter( tenant_id=tenant_id, @@ -1966,9 +1966,11 @@ class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): ) ) ) - if missing_scan_ids := scans_with_flag.filter(has_summary=False).values_list( - "id", flat=True - ): + missing_scan_ids = list( + scans_with_flag.filter(has_summary=False).values_list("id", flat=True) + ) + + if missing_scan_ids: for scan_id in missing_scan_ids: backfill_scan_resource_summaries_task.apply_async( kwargs={"tenant_id": tenant_id, "scan_id": scan_id} From beb0457aff5df06d99e0f021eab5f6ed6cfa3869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Fri, 16 May 2025 14:50:40 +0200 Subject: [PATCH 331/359] fix(findings): Fix latest metadata backfill condition and optimization (#7765) --- api/src/backend/api/v1/views.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 36fa3f08f9..04810f28df 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -1941,42 +1941,38 @@ class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): url_path="metadata/latest", ) def metadata_latest(self, request): - # Force filter validation - filtered_queryset = self.filter_queryset(self.get_queryset()) - tenant_id = request.tenant_id query_params = request.query_params - latest_scan_queryset = ( + latest_scans_queryset = ( Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED) .order_by("provider_id", "-inserted_at") .distinct("provider_id") ) + latest_scans_ids = list(latest_scans_queryset.values_list("id", flat=True)) queryset = ResourceScanSummary.objects.filter( tenant_id=tenant_id, - scan_id__in=latest_scan_queryset.values_list("id", flat=True), + scan_id__in=latest_scans_queryset.values_list("id", flat=True), ) # ToRemove: Temporary fallback mechanism - scans_with_flag = latest_scan_queryset.annotate( - has_summary=Exists( - ResourceScanSummary.objects.filter( - tenant_id=tenant_id, - scan_id=OuterRef("pk"), - ) + present_ids = set( + ResourceScanSummary.objects.filter( + tenant_id=tenant_id, scan_id__in=latest_scans_ids ) + .values_list("scan_id", flat=True) + .distinct() ) - missing_scan_ids = list( - scans_with_flag.filter(has_summary=False).values_list("id", flat=True) - ) - + missing_scan_ids = [sid for sid in latest_scans_ids if sid not in present_ids] if missing_scan_ids: for scan_id in missing_scan_ids: backfill_scan_resource_summaries_task.apply_async( kwargs={"tenant_id": tenant_id, "scan_id": scan_id} ) return Response( - get_findings_metadata_no_aggregations(tenant_id, filtered_queryset) + get_findings_metadata_no_aggregations( + tenant_id, self.filter_queryset(self.get_queryset()) + ) ) if service_filter := query_params.get("filter[service]") or query_params.get( From 451b36093ff533bb0cb3a0a46464abf3c623baf8 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 16 May 2025 14:57:15 +0200 Subject: [PATCH 332/359] feat(repository): add new check `repository_default_branch_requires_conversation_resolution` (#6208) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ires_conversation_resolution.metadata.json | 30 +++++ ...branch_requires_conversation_resolution.py | 42 +++++++ .../services/repository/repository_service.py | 7 ++ ...h_requires_conversation_resolution_test.py | 110 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 7 files changed, 192 insertions(+) create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.py create mode 100644 tests/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 2e00f9ce1a..f58d44f79c 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200) - Add `repository_default_branch_status_checks_required` check for GitHub provider. [(#6204)](https://github.com/prowler-cloud/prowler/pull/6204) - Add `repository_default_branch_protection_applies_to_admins` check for GitHub provider. [(#6205)](https://github.com/prowler-cloud/prowler/pull/6205) +- Add `repository_default_branch_requires_conversation_resolution` check for GitHub provider. [(#6208)](https://github.com/prowler-cloud/prowler/pull/6208) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/__init__.py b/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.metadata.json b/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.metadata.json new file mode 100644 index 0000000000..e240a6c0d1 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_default_branch_requires_conversation_resolution", + "CheckTitle": "Check if repository requires conversation resolution before merging", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "GitHubRepository", + "Description": "Ensure that the repository requires conversation resolution before merging.", + "Risk": "Leaving comments unresolved before merging code can lead to overlooked issues, including potential bugs or security vulnerabilities, that might affect the quality and security of the codebase. Unaddressed concerns could result in a lower quality of code, increasing the risk of production failures or breaches.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-conversation-resolution-before-merging", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that all comments in a code change proposal are resolved before merging. This guarantees that every reviewer’s concern is addressed, improving code quality and security by preventing issues from being ignored or overlooked.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.py b/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.py new file mode 100644 index 0000000000..1bee931478 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution.py @@ -0,0 +1,42 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_default_branch_requires_conversation_resolution(Check): + """Check if a repository requires conversation resolution + + This class verifies whether each repository requires conversation resolution. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Merging Requires Conversation Resolution check + + Iterates over all repositories and checks if they require conversation resolution. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + if repo.conversation_resolution is not None: + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does not require conversation resolution." + ) + + if repo.conversation_resolution: + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does require conversation resolution." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 3adcc8a968..31e9dd59a7 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -38,6 +38,7 @@ class Repository(GithubService): branch_deletion = True status_checks = False enforce_admins = False + conversation_resolution = False try: branch = repo.get_branch(default_branch) if branch.protected: @@ -60,6 +61,9 @@ class Repository(GithubService): protection.required_status_checks is not None ) enforce_admins = protection.enforce_admins + conversation_resolution = ( + protection.required_conversation_resolution + ) branch_protection = True except Exception as error: # If the branch is not found, it is not protected @@ -77,6 +81,7 @@ class Repository(GithubService): branch_deletion = None status_checks = None enforce_admins = None + conversation_resolution = None logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) @@ -95,6 +100,7 @@ class Repository(GithubService): default_branch_deletion=branch_deletion, status_checks=status_checks, enforce_admins=enforce_admins, + conversation_resolution=conversation_resolution, default_branch_protection=branch_protection, ) @@ -122,3 +128,4 @@ class Repo(BaseModel): status_checks: Optional[bool] enforce_admins: Optional[bool] approval_count: Optional[int] + conversation_resolution: Optional[bool] diff --git a/tests/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution_test.py b/tests/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution_test.py new file mode 100644 index 0000000000..2fe4b1dbd5 --- /dev/null +++ b/tests/providers/github/services/repository/repository_default_branch_requires_conversation_resolution/repository_default_branch_requires_conversation_resolution_test.py @@ -0,0 +1,110 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_default_branch_requires_conversation_resolution_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import ( + repository_default_branch_requires_conversation_resolution, + ) + + check = repository_default_branch_requires_conversation_resolution() + result = check.execute() + assert len(result) == 0 + + def test_conversation_resolution_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch=default_branch, + conversation_resolution=False, + private=False, + securitymd=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import ( + repository_default_branch_requires_conversation_resolution, + ) + + check = repository_default_branch_requires_conversation_resolution() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not require conversation resolution." + ) + + def test_conversation_resolution_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + default_branch = "main" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + private=False, + default_branch=default_branch, + conversation_resolution=True, + securitymd=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import ( + repository_default_branch_requires_conversation_resolution, + ) + + check = repository_default_branch_requires_conversation_resolution() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does require conversation resolution." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index a24c1625a7..30449e52bc 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -24,6 +24,7 @@ def mock_list_repositories(_): status_checks=True, approval_count=2, enforce_admins=True, + conversation_resolution=True, ), } @@ -55,4 +56,5 @@ class Test_Repository_Service: assert repository_service.repositories[1].default_branch_deletion assert repository_service.repositories[1].status_checks assert repository_service.repositories[1].enforce_admins + assert repository_service.repositories[1].conversation_resolution assert repository_service.repositories[1].approval_count == 2 From 637ebdc3db94d93a40d48f5b8e4a5e47e305de79 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 16 May 2025 15:03:37 +0200 Subject: [PATCH 333/359] feat(repository): add new check `repository_branch_delete_on_merge_enabled` (#6209) Co-authored-by: MrCloudSec --- prowler/CHANGELOG.md | 1 + prowler/providers/github/github_provider.py | 2 +- .../__init__.py | 0 ...anch_delete_on_merge_enabled.metadata.json | 30 +++++ ...pository_branch_delete_on_merge_enabled.py | 41 +++++++ .../services/repository/repository_service.py | 7 ++ ...ory_branch_delete_on_merge_enabled_test.py | 108 ++++++++++++++++++ .../repository/repository_service_test.py | 2 + 8 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/__init__.py create mode 100644 prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.metadata.json create mode 100644 prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.py create mode 100644 tests/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f58d44f79c..eff8d89188 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200) - Add `repository_default_branch_status_checks_required` check for GitHub provider. [(#6204)](https://github.com/prowler-cloud/prowler/pull/6204) - Add `repository_default_branch_protection_applies_to_admins` check for GitHub provider. [(#6205)](https://github.com/prowler-cloud/prowler/pull/6205) +- Add `repository_branch_delete_on_merge_enabled` check for GitHub provider. [(#6209)](https://github.com/prowler-cloud/prowler/pull/6209) - Add `repository_default_branch_requires_conversation_resolution` check for GitHub provider. [(#6208)](https://github.com/prowler-cloud/prowler/pull/6208) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) diff --git a/prowler/providers/github/github_provider.py b/prowler/providers/github/github_provider.py index 000f0e40d5..d34b2b3e66 100644 --- a/prowler/providers/github/github_provider.py +++ b/prowler/providers/github/github_provider.py @@ -247,7 +247,7 @@ class GithubProvider(Provider): if not session_token: # OAUTH logger.info( - "Looking for GITHUB_OAUTH_TOKEN environment variable as user has not provided any token...." + "Looking for GITHUB_OAUTH_APP_TOKEN environment variable as user has not provided any token...." ) session_token = environ.get("GITHUB_OAUTH_APP_TOKEN", "") if session_token: diff --git a/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/__init__.py b/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.metadata.json b/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.metadata.json new file mode 100644 index 0000000000..d5cff9a106 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "github", + "CheckID": "repository_branch_delete_on_merge_enabled", + "CheckTitle": "Check if a repository deletes the branch after merging", + "CheckType": [], + "ServiceName": "repository", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "GitHubRepository", + "Description": "Ensure that the repository deletes the branch after merging.", + "Risk": "Inactive branches pose a security risk as they can accumulate outdated code, dependencies, and potential vulnerabilities over time. Malicious actors may exploit these branches, and they can clutter the repository, making it harder to manage and track the active code. Additionally, stale branches may unintentionally be accessed or used inappropriately, leading to potential security breaches.", + "RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Regularly review and remove inactive branches from your repositories. This helps reduce the risk of malicious code injection, sensitive data leaks, and unnecessary clutter in the repository. By keeping branches active and up to date, you ensure that your codebase remains secure and manageable.", + "Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.py b/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.py new file mode 100644 index 0000000000..5b561927c3 --- /dev/null +++ b/prowler/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled.py @@ -0,0 +1,41 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGithub +from prowler.providers.github.services.repository.repository_client import ( + repository_client, +) + + +class repository_branch_delete_on_merge_enabled(Check): + """Check if a repository deletes branches on merge + + This class verifies whether each repository deletes branches on merge. + """ + + def execute(self) -> List[CheckReportGithub]: + """Execute the Github Repository Deletes Branch On Merge check + + Iterates over all repositories and checks if they delete branches on merge. + + Returns: + List[CheckReportGithub]: A list of reports for each repository + """ + findings = [] + for repo in repository_client.repositories.values(): + report = CheckReportGithub( + metadata=self.metadata(), resource=repo, repository=repo.name + ) + report.status = "FAIL" + report.status_extended = ( + f"Repository {repo.name} does not delete branches on merge." + ) + + if repo.delete_branch_on_merge: + report.status = "PASS" + report.status_extended = ( + f"Repository {repo.name} does delete branches on merge." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/github/services/repository/repository_service.py b/prowler/providers/github/services/repository/repository_service.py index 31e9dd59a7..571dda3429 100644 --- a/prowler/providers/github/services/repository/repository_service.py +++ b/prowler/providers/github/services/repository/repository_service.py @@ -18,6 +18,11 @@ class Repository(GithubService): for client in self.clients: for repo in client.get_user().get_repos(): default_branch = repo.default_branch + delete_branch_on_merge = ( + repo.delete_branch_on_merge + if repo.delete_branch_on_merge is not None + else False + ) securitymd_exists = False try: securitymd_exists = repo.get_contents("SECURITY.md") is not None @@ -102,6 +107,7 @@ class Repository(GithubService): enforce_admins=enforce_admins, conversation_resolution=conversation_resolution, default_branch_protection=branch_protection, + delete_branch_on_merge=delete_branch_on_merge, ) except Exception as error: @@ -128,4 +134,5 @@ class Repo(BaseModel): status_checks: Optional[bool] enforce_admins: Optional[bool] approval_count: Optional[int] + delete_branch_on_merge: Optional[bool] conversation_resolution: Optional[bool] diff --git a/tests/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled_test.py b/tests/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled_test.py new file mode 100644 index 0000000000..fc9a5c3ddd --- /dev/null +++ b/tests/providers/github/services/repository/repository_branch_delete_on_merge_enabled/repository_branch_delete_on_merge_enabled_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from prowler.providers.github.services.repository.repository_service import Repo +from tests.providers.github.github_fixtures import set_mocked_github_provider + + +class Test_repository_branch_delete_on_merge_enabled_test: + def test_no_repositories(self): + repository_client = mock.MagicMock + repository_client.repositories = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import ( + repository_branch_delete_on_merge_enabled, + ) + + check = repository_branch_delete_on_merge_enabled() + result = check.execute() + assert len(result) == 0 + + def test_branch_deletion_disabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch="main", + private=False, + securitymd=False, + delete_branch_on_merge=False, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import ( + repository_branch_delete_on_merge_enabled, + ) + + check = repository_branch_delete_on_merge_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Repository {repo_name} does not delete branches on merge." + ) + + def test_branch_deletion_enabled(self): + repository_client = mock.MagicMock + repo_name = "repo1" + repository_client.repositories = { + 1: Repo( + id=1, + name=repo_name, + full_name="account-name/repo1", + default_branch="main", + private=False, + securitymd=True, + delete_branch_on_merge=True, + ), + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_github_provider(), + ), + mock.patch( + "prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client", + new=repository_client, + ), + ): + from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import ( + repository_branch_delete_on_merge_enabled, + ) + + check = repository_branch_delete_on_merge_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == 1 + assert result[0].resource_name == "repo1" + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Repository {repo_name} does delete branches on merge." + ) diff --git a/tests/providers/github/services/repository/repository_service_test.py b/tests/providers/github/services/repository/repository_service_test.py index 30449e52bc..bcc3b19791 100644 --- a/tests/providers/github/services/repository/repository_service_test.py +++ b/tests/providers/github/services/repository/repository_service_test.py @@ -24,6 +24,7 @@ def mock_list_repositories(_): status_checks=True, approval_count=2, enforce_admins=True, + delete_branch_on_merge=True, conversation_resolution=True, ), } @@ -56,5 +57,6 @@ class Test_Repository_Service: assert repository_service.repositories[1].default_branch_deletion assert repository_service.repositories[1].status_checks assert repository_service.repositories[1].enforce_admins + assert repository_service.repositories[1].delete_branch_on_merge assert repository_service.repositories[1].conversation_resolution assert repository_service.repositories[1].approval_count == 2 From 97baa8a1e61f79679a1f0bc5d91024749bf723cb Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Fri, 16 May 2025 15:09:48 +0200 Subject: [PATCH 334/359] chore(ec2): improve severity logic in SG all ports open check (#7764) --- prowler/CHANGELOG.md | 1 + ...llow_ingress_from_internet_to_all_ports.metadata.json | 2 +- ...ritygroup_allow_ingress_from_internet_to_all_ports.py | 9 ++++++--- ...roup_allow_ingress_from_internet_to_all_ports_test.py | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index eff8d89188..f5d30ad653 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) - Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750) +- Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764) --- diff --git a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.metadata.json b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.metadata.json index c0dfb55761..6b295afc6d 100644 --- a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.metadata.json +++ b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.metadata.json @@ -8,7 +8,7 @@ "ServiceName": "ec2", "SubServiceName": "securitygroup", "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", - "Severity": "high", + "Severity": "critical", "ResourceType": "AwsEc2SecurityGroup", "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to all ports.", "Risk": "If Security groups are not properly configured the attack surface is increased. An attacker could exploit this misconfiguration to gain unauthorized access to resources.", diff --git a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.py b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.py index 943cc9b9d0..e9e7d47609 100644 --- a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.py +++ b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports.py @@ -1,4 +1,4 @@ -from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.lib.check.models import Check, Check_Report_AWS, Severity from prowler.providers.aws.services.ec2.ec2_client import ec2_client from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group from prowler.providers.aws.services.vpc.vpc_client import vpc_client @@ -9,14 +9,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_all_ports(Check): findings = [] for security_group_arn, security_group in ec2_client.security_groups.items(): # Check if ignoring flag is set and if the VPC and the SG is in use - if ec2_client.provider.scan_unused_services or ( + sg_in_use = ( security_group.vpc_id in vpc_client.vpcs and vpc_client.vpcs[security_group.vpc_id].in_use and len(security_group.network_interfaces) > 0 - ): + ) + if ec2_client.provider.scan_unused_services or sg_in_use: report = Check_Report_AWS( metadata=self.metadata(), resource=security_group ) + if not sg_in_use: + report.check_metadata.Severity = Severity.high report.resource_details = security_group.name report.status = "PASS" report.status_extended = f"Security group {security_group.name} ({security_group.id}) does not have all ports open to the Internet." diff --git a/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports_test.py b/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports_test.py index 85c1fd3c3d..98bfe0907e 100644 --- a/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports_test.py +++ b/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_all_ports/ec2_securitygroup_allow_ingress_from_internet_to_all_ports_test.py @@ -269,6 +269,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports: == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:security-group/{default_sg_id}" ) assert sg.resource_details == default_sg_name + assert sg.check_metadata.Severity == "high" assert sg.resource_tags == [] @mock_aws @@ -361,6 +362,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports: assert len(result) == 1 assert result[0].status == "PASS" assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].check_metadata.Severity == "critical" @mock_aws def test_set_failed_check_called_correctly(self): @@ -409,7 +411,6 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports: "prowler.providers.aws.lib.service.service.AWSService.set_failed_check" ) as mock_set_failed_check, ): - from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_all_ports.ec2_securitygroup_allow_ingress_from_internet_to_all_ports import ( ec2_securitygroup_allow_ingress_from_internet_to_all_ports, ) From 0490ab6944a75ee5d5df6510f3e11aa0cb6b3d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 19 May 2025 09:17:14 +0200 Subject: [PATCH 335/359] docs(checks): improve docs related with checks (#7768) --- docs/tutorials/misc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/misc.md b/docs/tutorials/misc.md index 5b17592548..2f646aab10 100644 --- a/docs/tutorials/misc.md +++ b/docs/tutorials/misc.md @@ -38,11 +38,11 @@ prowler --list-checks ``` - Execute specific check(s): ```console -prowler -c/--checks s3_bucket_public_access +prowler -c/--checks s3_bucket_public_access iam_root_mfa_enabled ``` - Exclude specific check(s): ```console -prowler -e/--excluded-checks ec2 rds +prowler -e/--excluded-checks s3_bucket_public_access iam_root_mfa_enabled ``` - Execute checks that appears in a json file: ```json From e5f1c2b19ca666302afda04fe62dc9cb7b69be16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Mon, 19 May 2025 09:41:56 +0200 Subject: [PATCH 336/359] feat(aws): add CIS 5.0 compliance framework (#7766) --- README.md | 2 +- dashboard/compliance/cis_5_0_aws.py | 24 + prowler/CHANGELOG.md | 1 + prowler/compliance/aws/cis_5.0_aws.json | 1415 +++++++++++++++++++++++ 4 files changed, 1441 insertions(+), 1 deletion(-) create mode 100644 dashboard/compliance/cis_5_0_aws.py create mode 100644 prowler/compliance/aws/cis_5.0_aws.json diff --git a/README.md b/README.md index 7fef33c6ae..82db510e66 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ prowler dashboard | Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | |---|---|---|---|---| -| AWS | 564 | 82 | 33 | 10 | +| AWS | 564 | 82 | 34 | 10 | | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | | Kubernetes | 83 | 7 | 4 | 7 | diff --git a/dashboard/compliance/cis_5_0_aws.py b/dashboard/compliance/cis_5_0_aws.py new file mode 100644 index 0000000000..94558f33ad --- /dev/null +++ b/dashboard/compliance/cis_5_0_aws.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_cis + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f5d30ad653..55107c7b56 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add `repository_default_branch_requires_conversation_resolution` check for GitHub provider. [(#6208)](https://github.com/prowler-cloud/prowler/pull/6208) - Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304) - Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116) +- Add CIS 5.0 compliance framework for AWS. [(7766)](https://github.com/prowler-cloud/prowler/pull/7766) ### Fixed - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) diff --git a/prowler/compliance/aws/cis_5.0_aws.json b/prowler/compliance/aws/cis_5.0_aws.json new file mode 100644 index 0000000000..b95feddd27 --- /dev/null +++ b/prowler/compliance/aws/cis_5.0_aws.json @@ -0,0 +1,1415 @@ +{ + "Framework": "CIS", + "Version": "5.0", + "Provider": "AWS", + "Description": "The CIS Amazon Web Services Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Amazon Web Services with an emphasis on foundational, testable, and architecture agnostic settings.", + "Requirements": [ + { + "Id": "1.1", + "Description": "Maintain current contact details", + "Checks": [ + "account_maintain_current_contact_details" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of the Acceptable Use Policy or indicative of a likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.", + "RationaleStatement": "If an AWS account is observed to be behaving in a prohibited or suspicious manner, AWS will attempt to contact the account owner by email and phone using the contact details listed. If this is unsuccessful and the account behavior needs urgent mitigation, proactive measures may be taken, including throttling of traffic between the account exhibiting suspicious behavior and the AWS API endpoints and the Internet. This will result in impaired service to and from the account in question, so it is in both the customers' and AWS's best interests that prompt contact can be established. This is best achieved by setting AWS account contact details to point to resources which have multiple individuals as recipients, such as email aliases and PABX hunt groups.", + "ImpactStatement": "", + "RemediationProcedure": "This activity can only be performed via the AWS Console, with a user who has permission to read and write Billing information (aws-portal:\\*Billing). 1. Sign in to the AWS Management Console and open the `Billing and Cost Management` console at https://console.aws.amazon.com/billing/home#/. 2. On the navigation bar, choose your account name, and then choose `Account`. 3. On the `Account Settings` page, next to `Account Settings`, choose `Edit`. 4. Next to the field that you need to update, choose `Edit`. 5. After you have entered your changes, choose `Save changes`. 6. After you have made your changes, choose `Done`. 7. To edit your contact information, under `Contact Information`, choose `Edit`. 8. For the fields that you want to change, type your updated information, and then choose `Update`.", + "AuditProcedure": "This activity can only be performed via the AWS Console, with a user who has permission to read and write Billing information (aws-portal:\\*Billing). 1. Sign in to the AWS Management Console and open the `Billing and Cost Management` console at https://console.aws.amazon.com/billing/home#/. 2. On the navigation bar, choose your account name, and then choose `Account`. 3. On the `Account Settings` page, review and verify the current details. 4. Under `Contact Information`, review and verify the current details.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/manage-account-payment.html#contact-info", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.2", + "Description": "Ensure security contact information is registered", + "Checks": [ + "account_security_contact_information_is_registered" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.", + "RationaleStatement": "Specifying security-specific contact information will help ensure that security advisories sent by AWS reach the team in your organization that is best equipped to respond to them.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to establish security contact information: **From Console:** 1. Click on your account name at the top right corner of the console. 2. From the drop-down menu Click `My Account` 3. Scroll down to the `Alternate Contacts` section 4. Enter contact information in the `Security` section **From Command Line:** Run the following command with the following input parameters: --email-address, --name, and --phone-number. ``` aws account put-alternate-contact --alternate-contact-type SECURITY ``` **Note:** Consider specifying an internal email distribution list to ensure emails are regularly monitored by more than one individual.", + "AuditProcedure": "Perform the following to determine if security contact information is present: **From Console:** 1. Click on your account name at the top right corner of the console 2. From the drop-down menu Click `My Account` 3. Scroll down to the `Alternate Contacts` section 4. Ensure contact information is specified in the `Security` section **From Command Line:** 1. Run the following command: ``` aws account get-alternate-contact --alternate-contact-type SECURITY ``` 2. Ensure proper contact information is specified for the `Security` contact.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.3", + "Description": "Ensure no 'root' user account access key exists", + "Checks": [ + "iam_no_root_access_key" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted.", + "RationaleStatement": "Deleting access keys associated with the 'root' user account limits vectors by which the account can be compromised. Additionally, deleting the 'root' access keys encourages the creation and use of role based accounts that are least privileged.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to delete active 'root' user access keys. **From Console:** 1. Sign in to the AWS Management Console as 'root' and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. Click on `` at the top right and select `My Security Credentials` from the drop down list. 3. On the pop out screen Click on `Continue to Security Credentials`. 4. Click on `Access Keys` (Access Key ID and Secret Access Key). 5. If there are active keys, under `Status`, click `Delete` (Note: Deleted keys cannot be recovered). Note: While a key can be made inactive, this inactive key will still show up in the CLI command from the audit procedure, and may lead to the root user being falsely flagged as being non-compliant.", + "AuditProcedure": "Perform the following to determine if the 'root' user account has access keys: **From Console:** 1. Login to the AWS Management Console. 2. Click `Services`. 3. Click `IAM`. 4. Click on `Credential Report`. 5. This will download a `.csv` file which contains credential usage for all IAM users within an AWS Account - open this file. 6. For the `` user, ensure the `access_key_1_active` and `access_key_2_active` fields are set to `FALSE`. **From Command Line:** Run the following command: ``` aws iam get-account-summary | grep AccountAccessKeysPresent ``` If no 'root' access keys exist the output will show `AccountAccessKeysPresent: 0,`. If the output shows a 1, then 'root' keys exist and should be deleted.", + "AdditionalInformation": "- IAM User account root for us-gov cloud regions is not enabled by default. However, on request to AWS support enables 'root' access only through access-keys (CLI, API methods) for us-gov cloud region. - Implement regular checks and alerts for any creation of new root access keys to promptly address any unauthorized or accidental creation.", + "References": "http://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html:http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html:http://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccountSummary.html:https://aws.amazon.com/blogs/security/an-easier-way-to-determine-the-presence-of-aws-account-access-keys/", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.4", + "Description": "Ensure MFA is enabled for the 'root' user account", + "Checks": [ + "iam_root_mfa_enabled" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is kept charged and secured, independent of any individual personal devices (non-personal virtual MFA). This lessens the risks of losing access to the MFA due to device loss, device trade-in, or if the individual owning the device is no longer employed at the company. Where an AWS Organization is using centralized root access, root credentials can be removed from member accounts. In that case it is neither possible nor necessary to configure root MFA in the member account.", + "RationaleStatement": "Enabling MFA provides increased security for console access as it requires the authenticating principal to possess a device that emits a time-sensitive key and have knowledge of a credential.", + "ImpactStatement": "", + "RemediationProcedure": "**Note:** To manage MFA devices for the 'root' AWS account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials. Perform the following to establish MFA for the 'root' user account: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. Choose `Dashboard` , and under `Security Status` , expand `Activate MFA` on your root account. 3. Choose `Activate MFA` 4. In the wizard, choose `A virtual MFA` device and then choose `Next Step` . 5. IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the 'secret configuration key' that is available for manual entry on devices that do not support QR codes. 6. Open your virtual MFA application. (For a list of apps that you can use for hosting virtual MFA devices, see [Virtual MFA Applications](http://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications).) If the virtual MFA application supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device). 7. Determine whether the MFA app supports QR codes, and then do one of the following: - Use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to Scan code, and then use the device's camera to scan the code. - In the Manage MFA Device wizard, choose Show secret key for manual configuration, and then type the secret configuration key into your MFA application. When you are finished, the virtual MFA device starts generating one-time passwords. In the Manage MFA Device wizard, in the Authentication Code 1 box, type the one-time password that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password. Then type the second one-time password into the Authentication Code 2 box. Choose Assign Virtual MFA.", + "AuditProcedure": "Perform the following to determine if the 'root' user account is enabled and has MFA setup: **From Console:** 1. Login to the AWS Management Console 2. Click `Services` 3. Click `IAM` 4. Click on `Credential Report` 5. This will download a `.csv` file which contains credential usage for all IAM users within an AWS Account - open this file 6. For the `` user, ensure the `mfa_active` field is set to `TRUE` or the `password_enabled` field is set to `FALSE` **From Command Line:** 1. Run the following command: ``` aws iam get-account-summary | grep AccountMFAEnabled aws iam get-account-summary | grep AccountPasswordPresent ``` 2. Ensure the AccountMFAEnabled property is set to 1 or the AccountPasswordPresent property is set to 0", + "AdditionalInformation": "IAM User account root for us-gov cloud regions does not have console access. This recommendation is not applicable for us-gov cloud regions.", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html#enable-virt-mfa-for-root:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-enable-root-access.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.5", + "Description": "Ensure hardware MFA is enabled for the 'root' user account", + "Checks": [ + "iam_root_hardware_mfa_enabled" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA. Where an AWS Organization is using centralized root access, root credentials can be removed from member accounts. In that case it is neither possible nor necessary to configure root MFA in the member account.", + "RationaleStatement": "A hardware MFA has a smaller attack surface than a virtual MFA. For example, a hardware MFA does not suffer the attack surface introduced by the mobile smartphone on which a virtual MFA resides. **Note**: Using hardware MFA for numerous AWS accounts may create a logistical device management issue. If this is the case, consider implementing this Level 2 recommendation selectively for the highest security AWS accounts, while applying the Level 1 recommendation to the remaining accounts.", + "ImpactStatement": "", + "RemediationProcedure": "**Note:** To manage MFA devices for the AWS 'root' user account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials. Perform the following to establish a hardware MFA for the 'root' user account: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. Choose `Dashboard`, and under `Security Status`, expand `Activate MFA` on your root account. 3. Choose `Activate MFA`. 4. In the wizard, choose `A hardware MFA` device and then choose `Next Step`. 5. In the `Serial Number` box, enter the serial number that is found on the back of the MFA device. 6. In the `Authentication Code 1` box, enter the six-digit number displayed by the MFA device. You might need to press the button on the front of the device to display the number. 7. Wait 30 seconds while the device refreshes the code, and then enter the next six-digit number into the `Authentication Code 2` box. You might need to press the button on the front of the device again to display the second number. 8. Choose `Next Step`. The MFA device is now associated with the AWS account. The next time you use your AWS account credentials to sign in, you must type a code from the hardware MFA device. Remediation for this recommendation is not available through AWS CLI.", + "AuditProcedure": "Perform the following to determine if the 'root' user account has a hardware MFA setup: 1. Run the following command to determine if the 'root' account has MFA setup: ``` aws iam get-account-summary | grep AccountMFAEnabled aws iam get-account-summary | grep AccountPasswordPresent ``` The `AccountMFAEnabled` property is set to `1` will ensure that the 'root' user account has MFA (Virtual or Hardware) Enabled. `AccountPasswordPresent` set to `0` indicates that the `root` console credential has been removed. If `AccountMFAEnabled` property is set to `0` and `AccountPasswordPresent` is set to `1` the account is not compliant with this recommendation. 2. If `AccountMFAEnabled` property is set to `1`, determine 'root' account has Hardware MFA enabled. Run the following command to list all virtual MFA devices: ``` aws iam list-virtual-mfa-devices ``` If the output contains one MFA with the following Serial Number, it means the MFA is virtual, not hardware and the account is not compliant with this recommendation: `SerialNumber: arn:aws:iam::__:mfa/root-account-mfa-device`", + "AdditionalInformation": "IAM User account 'root' for us-gov cloud regions does not have console access. This control is not applicable for us-gov cloud regions.", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html#enable-hw-mfa-for-root:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-enable-root-access.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.6", + "Description": "Eliminate use of the 'root' user for administrative and daily tasks", + "Checks": [ + "iam_avoid_root_usage" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.", + "RationaleStatement": "The 'root user' has unrestricted access to and control over all account resources. Use of it is inconsistent with the principles of least privilege and separation of duties, and can lead to unnecessary harm due to error or account compromise.", + "ImpactStatement": "", + "RemediationProcedure": "If you find that the 'root' user account is being used for daily activities, including administrative tasks that do not require the 'root' user: 1. Change the 'root' user password. 2. Deactivate or delete any access keys associated with the 'root' user. Remember, anyone who has 'root' user credentials for your AWS account has unrestricted access to and control of all the resources in your account, including billing information.", + "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console at `https://console.aws.amazon.com/iam/`. 2. In the left pane, click `Credential Report`. 3. Click on `Download Report`. 4. Open or Save the file locally. 5. Locate the `` under the user column. 6. Review `password_last_used, access_key_1_last_used_date, access_key_2_last_used_date` to determine when the 'root user' was last used. **From Command Line:** Run the following CLI commands to provide a credential report for determining the last time the 'root user' was used: ``` aws iam generate-credential-report ``` ``` aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,5,11,16 | grep -B1 '' ``` Review `password_last_used`, `access_key_1_last_used_date`, `access_key_2_last_used_date` to determine when the _root user_ was last used. **Note:** There are a few conditions under which the use of the 'root' user account is required. Please see the reference links for all of the tasks that require use of the 'root' user.", + "AdditionalInformation": "The 'root' user for us-gov cloud regions is not enabled by default. However, on request to AWS support, they can enable the 'root' user and grant access only through access-keys (CLI, API methods) for us-gov cloud region. If the 'root' user for us-gov cloud regions is enabled, this recommendation is applicable. Monitoring usage of the 'root' user can be accomplished by implementing recommendation 3.3 Ensure a log metric filter and alarm exist for usage of the 'root' user.", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html:https://docs.aws.amazon.com/general/latest/gr/aws_tasks-that-require-root.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.7", + "Description": "Ensure IAM password policy requires minimum length of 14 or greater", + "Checks": [ + "iam_password_policy_minimum_length_14" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are at least a given length. It is recommended that the password policy require a minimum password length 14.", + "RationaleStatement": "Setting a password complexity policy increases account resiliency against brute force login attempts.", + "ImpactStatement": "Enforcing a minimum password length of 14 characters enhances security by making passwords more resistant to brute force attacks. However, it may require users to create longer and potentially more complex passwords, which could impact user convenience.", + "RemediationProcedure": "Perform the following to set the password policy as prescribed: **From Console:** 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Set Minimum password length to `14` or greater. 5. Click Apply password policy **From Command Line:** ``` aws iam update-account-password-policy --minimum-password-length 14 ``` Note: All commands starting with aws iam update-account-password-policy can be combined into a single command.", + "AuditProcedure": "Perform the following to ensure the password policy is configured as prescribed: **From Console:** 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Ensure Minimum password length is set to 14 or greater. **From Command Line:** ``` aws iam get-account-password-policy ``` Ensure the output of the above command includes MinimumPasswordLength: 14 (or higher)", + "AdditionalInformation": "Ensure the password policy also includes requirements for password complexity, such as the inclusion of uppercase letters, lowercase letters, numbers, and special characters: ``` aws iam update-account-password-policy --require-uppercase-characters --require-lowercase-characters --require-numbers --require-symbols ```", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.8", + "Description": "Ensure IAM password policy prevents password reuse", + "Checks": [ + "iam_password_policy_reuse_24" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.", + "RationaleStatement": "Preventing password reuse increases account resiliency against brute force login attempts.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to set the password policy as prescribed: **From Console:** 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Check Prevent password reuse 5. Set Number of passwords to remember is set to `24` **From Command Line:** ``` aws iam update-account-password-policy --password-reuse-prevention 24 ``` Note: All commands starting with aws iam update-account-password-policy can be combined into a single command.", + "AuditProcedure": "Perform the following to ensure the password policy is configured as prescribed: **From Console:** 1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Ensure Prevent password reuse is checked 5. Ensure Number of passwords to remember is set to 24 **From Command Line:** ``` aws iam get-account-password-policy ``` Ensure the output of the above command includes PasswordReusePrevention: 24", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.9", + "Description": "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password", + "Checks": [ + "iam_user_mfa_enabled_console_access" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.", + "RationaleStatement": "Enabling MFA provides increased security for console access as it requires the authenticating principal to possess a device that displays a time-sensitive key and have knowledge of a credential.", + "ImpactStatement": "AWS will soon end support for SMS multi-factor authentication (MFA). New customers are not allowed to use this feature. We recommend that existing customers switch to an alternative method of MFA.", + "RemediationProcedure": "Perform the following to enable MFA: **From Console:** 1. Sign in to the AWS Management Console and open the IAM console at 'https://console.aws.amazon.com/iam/' 2. In the left pane, select `Users`. 3. In the `User Name` list, choose the name of the intended MFA user. 4. Choose the `Security Credentials` tab, and then choose `Manage MFA Device`. 5. In the `Manage MFA Device wizard`, choose `Virtual MFA` device, and then choose `Continue`. IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the 'secret configuration key' that is available for manual entry on devices that do not support QR codes. 6. Open your virtual MFA application. (For a list of apps that you can use for hosting virtual MFA devices, see Virtual MFA Applications at https://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications). If the virtual MFA application supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device). 7. Determine whether the MFA app supports QR codes, and then do one of the following: - Use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to Scan code, and then use the device's camera to scan the code. - In the Manage MFA Device wizard, choose Show secret key for manual configuration, and then type the secret configuration key into your MFA application. When you are finished, the virtual MFA device starts generating one-time passwords. 8. In the `Manage MFA Device wizard`, in the `MFA Code 1 box`, type the `one-time password` that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password. Then type the second `one-time password` into the `MFA Code 2 box`. 9. Click `Assign MFA`.", + "AuditProcedure": "Perform the following to determine if a MFA device is enabled for all IAM users having a console password: **From Console:** 1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. In the left pane, select `Users` 3. If the `MFA` or `Password age` columns are not visible in the table, click the gear icon at the upper right corner of the table and ensure a checkmark is next to both, then click `Close`. 4. Ensure that for each user where the `Password age` column shows a password age, the `MFA` column shows `Virtual`, `U2F Security Key`, or `Hardware`. **From Command Line:** 1. Run the following command (OSX/Linux/UNIX) to generate a list of all IAM users along with their password and MFA status: ``` aws iam generate-credential-report ``` ``` aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,4,8 ``` 2. The output of this command will produce a table similar to the following: ``` user,password_enabled,mfa_active elise,false,false brandon,true,true rakesh,false,false helene,false,false paras,true,true anitha,false,false ``` 3. For any column having `password_enabled` set to `true` , ensure `mfa_active` is also set to `true.`", + "AdditionalInformation": "**Forced IAM User Self-Service Remediation** Amazon has published a pattern that requires users to set up MFA through self-service before they gain access to their complete set of permissions. Until they complete this step, they cannot access their full permissions. This pattern can be used for new AWS accounts. It can also be applied to existing accounts; it is recommended that users receive instructions and a grace period to complete MFA enrollment before active enforcement on existing AWS accounts.", + "References": "https://tools.ietf.org/html/rfc6238:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html:https://blogs.aws.amazon.com/security/post/Tx2SJJYE082KBUK/How-to-Delegate-Management-of-Multi-Factor-Authentication-to-AWS-IAM-Users", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.1", + "Description": "Do not create access keys during initial setup for IAM users with a console password", + "Checks": [ + "iam_user_no_setup_initial_access_key" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.", + "RationaleStatement": "Requiring the additional steps to be taken by the user for programmatic access after their profile has been created will provide a stronger indication of intent that access keys are [a] necessary for their work and [b] that once the access key is established on an account, the keys may be in use somewhere in the organization. **Note**: Even if it is known the user will need access keys, require them to create the keys themselves or put in a support ticket to have them created as a separate step from user creation.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to delete access keys that do not pass the audit: **From Console:** 1. Login to the AWS Management Console: 2. Click `Services` 3. Click `IAM` 4. Click on `Users` 5. Click on `Security Credentials` 6. As an Administrator - Click on the X `(Delete)` for keys that were created at the same time as the user profile but have not been used. 7. As an IAM User - Click on the X `(Delete)` for keys that were created at the same time as the user profile but have not been used. **From Command Line:** ``` aws iam delete-access-key --access-key-id --user-name ```", + "AuditProcedure": "Perform the following steps to determine if unused access keys were created upon user creation: **From Console:** 1. Login to the AWS Management Console 2. Click `Services` 3. Click `IAM` 4. Click on a User where column `Password age` and `Access key age` is not set to `None` 5. Click on `Security credentials` Tab 6. Compare the user `Creation time` to the Access Key `Created` date. 6. For any that match, the key was created during initial user setup. - Keys that were created at the same time as the user profile and do not have a last used date should be deleted. Refer to the remediation below. **From Command Line:** 1. Run the following command (OSX/Linux/UNIX) to generate a list of all IAM users along with their access keys utilization: ``` aws iam generate-credential-report ``` ``` aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,4,9,11,14,16 ``` 2. The output of this command will produce a table similar to the following: ``` user,password_enabled,access_key_1_active,access_key_1_last_used_date,access_key_2_active,access_key_2_last_used_date elise,false,true,2015-04-16T15:14:00+00:00,false,N/A brandon,true,true,N/A,false,N/A rakesh,false,false,N/A,false,N/A helene,false,true,2015-11-18T17:47:00+00:00,false,N/A paras,true,true,2016-08-28T12:04:00+00:00,true,2016-03-04T10:11:00+00:00 anitha,true,true,2016-06-08T11:43:00+00:00,true,N/A ``` 3. For any user having `password_enabled` set to `true` AND `access_key_last_used_date` set to `N/A` refer to the remediation below.", + "AdditionalInformation": "Credential report does not appear to contain Key Creation Date", + "References": "https://docs.aws.amazon.com/cli/latest/reference/iam/delete-access-key.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.11", + "Description": "Ensure credentials unused for 45 days or more are disabled", + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused for 45 days or more be deactivated or removed.", + "RationaleStatement": "Disabling or removing unnecessary credentials will reduce the window of opportunity for credentials associated with a compromised or abandoned account to be used.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** Perform the following to manage Unused Password (IAM user console access) 1. Login to the AWS Management Console: 2. Click `Services` 3. Click `IAM` 4. Click on `Users` 5. Click on `Security Credentials` 6. Select user whose `Console last sign-in` is greater than 45 days 7. Click `Security credentials` 8. In section `Sign-in credentials`, `Console password` click `Manage` 9. Under Console Access select `Disable` 10. Click `Apply` Perform the following to deactivate Access Keys: 1. Login to the AWS Management Console: 2. Click `Services` 3. Click `IAM` 4. Click on `Users` 5. Click on `Security Credentials` 6. Select any access keys that are over 45 days old and that have been used and - Click on `Make Inactive` 7. Select any access keys that are over 45 days old and that have not been used and - Click the X to `Delete`", + "AuditProcedure": "Perform the following to determine if unused credentials exist: **From Console:** 1. Login to the AWS Management Console 2. Click `Services` 3. Click `IAM` 4. Click on `Users` 5. Click the `Settings` (gear) icon. 6. Select `Console last sign-in`, `Access key last used`, and `Access Key Id` 7. Click on `Close` 8. Check and ensure that `Console last sign-in` is less than 45 days ago. **Note** - `Never` means the user has never logged in. 9. Check and ensure that `Access key age` is less than 45 days and that `Access key last used` does not say `None` If the user hasn't signed into the Console in the last 45 days or Access keys are over 45 days old refer to the remediation. **From Command Line:** **Download Credential Report:** 1. Run the following commands: ``` aws iam generate-credential-report aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,4,5,6,9,10,11,14,15,16 | grep -v '^' ``` **Ensure unused credentials do not exist:** 2. For each user having `password_enabled` set to `TRUE` , ensure `password_last_used_date` is less than `45` days ago. - When `password_enabled` is set to `TRUE` and `password_last_used` is set to `No_Information` , ensure `password_last_changed` is less than 45 days ago. 3. For each user having an `access_key_1_active` or `access_key_2_active` to `TRUE` , ensure the corresponding `access_key_n_last_used_date` is less than `45` days ago. - When a user having an `access_key_x_active` (where x is 1 or 2) to `TRUE` and corresponding access_key_x_last_used_date is set to `N/A`, ensure `access_key_x_last_rotated` is less than 45 days ago.", + "AdditionalInformation": " is excluded in the audit since the root account should not be used for day-to-day business and would likely be unused for more than 45 days.", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#remove-credentials:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_admin-change-user.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.12", + "Description": "Ensure there is only one active access key for any single IAM user", + "Checks": [ + "iam_user_two_active_access_key" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)", + "RationaleStatement": "One of the best ways to protect your account is to not allow users to have multiple access keys.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Sign in to the AWS Management Console and navigate to IAM dashboard at `https://console.aws.amazon.com/iam/`. 2. In the left navigation panel, choose `Users`. 3. Click on the IAM user name that you want to examine. 4. On the IAM user configuration page, select `Security Credentials` tab. 5. In `Access Keys` section, choose one access key that is less than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working. 6. In the same `Access Keys` section, identify your non-operational access keys (other than the chosen one) and deactivate it by clicking the `Make Inactive` link. 7. If you receive the `Change Key Status` confirmation box, click `Deactivate` to switch off the selected key. 8. Repeat steps 3-7 for each IAM user in your AWS account. **From Command Line:** 1. Using the IAM user and access key information provided in the `Audit CLI`, choose one access key that is less than 90 days old. This should be the only active key used by this IAM user to access AWS resources programmatically. Test your application(s) to make sure that the chosen access key is working. 2. Run the `update-access-key` command below using the IAM user name and the non-operational access key IDs to deactivate the unnecessary key(s). Refer to the Audit section to identify the unnecessary access key ID for the selected IAM user **Note** - the command does not return any output: ``` aws iam update-access-key --access-key-id --status Inactive --user-name ``` 3. To confirm that the selected access key pair has been successfully `deactivated` run the `list-access-keys` audit command again for that IAM User: ``` aws iam list-access-keys --user-name ``` - The command output should expose the metadata for each access key associated with the IAM user. If the non-operational key pair(s) `Status` is set to `Inactive`, the key has been successfully deactivated and the IAM user access configuration adheres now to this recommendation. 4. Repeat steps 1-3 for each IAM user in your AWS account.", + "AuditProcedure": "**From Console:** 1. Sign in to the AWS Management Console and navigate to IAM dashboard at `https://console.aws.amazon.com/iam/`. 2. In the left navigation panel, choose `Users`. 3. Click on the IAM user name that you want to examine. 4. On the IAM user configuration page, select `Security Credentials` tab. 5. Under `Access Keys` section, in the Status column, check the current status for each access key associated with the IAM user. If the selected IAM user has more than one access key activated, then the user's access configuration does not adhere to security best practices, and the risk of accidental exposures increases. - Repeat steps 3-5 for each IAM user in your AWS account. **From Command Line:** 1. Run `list-users` command to list all IAM users within your account: ``` aws iam list-users --query Users[*].UserName ``` The command output should return an array that contains all your IAM user names. 2. Run `list-access-keys` command using the IAM user name list to return the current status of each access key associated with the selected IAM user: ``` aws iam list-access-keys --user-name ``` The command output should expose the metadata `(Username, AccessKeyId, Status, CreateDate)` for each access key on that user account. 3. Check the `Status` property value for each key returned to determine each key's current state. If the `Status` property value for more than one IAM access key is set to `Active`, the user access configuration does not adhere to this recommendation; refer to the remediation below. - Repeat steps 2 and 3 for each IAM user in your AWS account.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.13", + "Description": "Ensure access keys are rotated every 90 days or less", + "Checks": [ + "iam_rotate_access_key_90_days" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be rotated regularly.", + "RationaleStatement": "Rotating access keys will reduce the window of opportunity for an access key that is associated with a compromised or terminated account to be used. Access keys should be rotated to ensure that data cannot be accessed with an old key which might have been lost, cracked, or stolen.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to rotate access keys: **From Console:** 1. Go to the Management Console (https://console.aws.amazon.com/iam) 2. Click on `Users` 3. Click on `Security Credentials` 4. As an Administrator - Click on `Make Inactive` for keys that have not been rotated in `90` Days 5. As an IAM User - Click on `Make Inactive` or `Delete` for keys which have not been rotated or used in `90` Days 6. Click on `Create Access Key` 7. Update programmatic calls with new Access Key credentials **From Command Line:** 1. While the first access key is still active, create a second access key, which is active by default. Run the following command: ``` aws iam create-access-key ``` At this point, the user has two active access keys. 2. Update all applications and tools to use the new access key. 3. Determine whether the first access key is still in use by using this command: ``` aws iam get-access-key-last-used ``` 4. One approach is to wait several days and then check the old access key for any use before proceeding. Even if step 3 indicates no use of the old key, it is recommended that you do not immediately delete the first access key. Instead, change the state of the first access key to Inactive using this command: ``` aws iam update-access-key ``` 5. Use only the new access key to confirm that your applications are working. Any applications and tools that still use the original access key will stop working at this point because they no longer have access to AWS resources. If you find such an application or tool, you can switch its state back to Active to reenable the first access key. Then return to step 2 and update this application to use the new key. 6. After you wait some period of time to ensure that all applications and tools have been updated, you can delete the first access key with this command: ``` aws iam delete-access-key ```", + "AuditProcedure": "Perform the following to determine if access keys are rotated as prescribed: **From Console:** 1. Go to the Management Console (https://console.aws.amazon.com/iam) 2. Click on `Users` 3. For each user, go to `Security Credentials` 4. Review each key under `Access Keys` 5. For each key that shows `Active` for status, ensure that `Created` is less than or equal to `90 days ago`. **From Command Line:** ``` aws iam generate-credential-report aws iam get-credential-report --query 'Content' --output text | base64 -d ``` The `access_key_1_last_rotated` and the `access_key_2_last_rotated` fields in this file notes the date and time, in ISO 8601 date-time format, when the user's access key was created or last changed. If the user does not have an active access key, the value in this field is N/A (not applicable).", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#rotate-credentials:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_finding-unused.html:https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.14", + "Description": "Ensure IAM users receive permissions only through groups", + "Checks": [ + "iam_policy_attached_only_to_group_or_roles" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are four ways to define policies for a user: 1) Edit the user policy directly, also known as an inline or user policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy; 4) add the user to an IAM group that has an inline policy. Only the third implementation is recommended.", + "RationaleStatement": "Assigning IAM policies solely through groups unifies permissions management into a single, flexible layer that is consistent with organizational functional roles. By unifying permissions management, the likelihood of excessive permissions is reduced.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to create an IAM group and assign a policy to it: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. In the navigation pane, click `Groups` and then click `Create New Group`. 3. In the `Group Name` box, type the name of the group and then click `Next Step`. 4. In the list of policies, select the check box for each policy that you want to apply to all members of the group. Then click `Next Step`. 5. Click `Create Group`. Perform the following to add a user to a given group: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. In the navigation pane, click `Groups`. 3. Select the group to add a user to. 4. Click `Add Users To Group`. 5. Select the users to be added to the group. 6. Click `Add Users`. Perform the following to remove a direct association between a user and policy: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. In the left navigation pane, click on Users. 3. For each user: - Select the user - Click on the `Permissions` tab - Expand `Permissions policies` - Click `X` for each policy; then click Detach or Remove (depending on policy type)", + "AuditProcedure": "Perform the following to determine if an inline policy is set or a policy is directly attached to users: 1. Run the following to get a list of IAM users: ``` aws iam list-users --query 'Users[*].UserName' --output text ``` 2. For each user returned, run the following command to determine if any policies are attached to them: ``` aws iam list-attached-user-policies --user-name aws iam list-user-policies --user-name ``` 3. If any policies are returned, the user has an inline policy or direct policy attachment.", + "AdditionalInformation": "", + "References": "http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html:http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.15", + "Description": "Ensure IAM policies that allow full *:* administrative privileges are not attached", + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered standard security advice to grant least privilege—that is, granting only the permissions required to perform a task. Determine what users need to do, and then craft policies for them that allow the users to perform only those tasks, instead of granting full administrative privileges.", + "RationaleStatement": "It's more secure to start with a minimum set of permissions and grant additional permissions as necessary, rather than starting with permissions that are too lenient and then attempting to tighten them later. Providing full administrative privileges instead of restricting access to the minimum set of permissions required for the user exposes resources to potentially unwanted actions. IAM policies that contain a statement with `Effect: Allow` and `Action: *` over `Resource: *` should be removed.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** Perform the following to detach the policy that has full administrative privileges: 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. In the navigation pane, click Policies and then search for the policy name found in the audit step. 3. Select the policy that needs to be deleted. 4. In the policy action menu, select `Detach`. 5. Select all Users, Groups, Roles that have this policy attached. 6. Click `Detach Policy`. 7. Select the newly detached policy and select `Delete`. **From Command Line:** Perform the following to detach the policy that has full administrative privileges as found in the audit step: 1. Lists all IAM users, groups, and roles that the specified managed policy is attached to. ``` aws iam list-entities-for-policy --policy-arn ``` 2. Detach the policy from all IAM Users: ``` aws iam detach-user-policy --user-name --policy-arn ``` 3. Detach the policy from all IAM Groups: ``` aws iam detach-group-policy --group-name --policy-arn ``` 4. Detach the policy from all IAM Roles: ``` aws iam detach-role-policy --role-name --policy-arn ```", + "AuditProcedure": "Perform the following to determine existing policies: **From Command Line:** 1. Run the following to get a list of IAM policies: ``` aws iam list-policies --only-attached --output text ``` 2. For each policy returned, run the following command to determine if any policy is allowing full administrative privileges on the account: ``` aws iam get-policy-version --policy-arn --version-id ``` 3. In the output, the policy should not contain any Statement block with `Effect: Allow` and `Action` set to `*` and `Resource` set to `*`.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html:https://docs.aws.amazon.com/cli/latest/reference/iam/index.html#cli-aws-iam", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.16", + "Description": "Ensure a support role has been created to manage incidents with AWS Support", + "Checks": [ + "iam_support_role_created" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role, with the appropriate policy assigned, to allow authorized users to manage incidents with AWS Support.", + "RationaleStatement": "By implementing least privilege for access control, an IAM Role will require an appropriate IAM Policy to allow Support Center Access in order to manage Incidents with AWS Support.", + "ImpactStatement": "All AWS Support plans include an unlimited number of account and billing support cases, with no long-term contracts. Support billing calculations are performed on a per-account basis for all plans. Enterprise Support plan customers have the option to include multiple enabled accounts in an aggregated monthly billing calculation. Monthly charges for the Business and Enterprise support plans are based on each month's AWS usage charges, subject to a monthly minimum, billed in advance. When assigning rights, keep in mind that other policies may grant access to Support as well. This may include AdministratorAccess and other policies including customer managed policies. Utilizing the AWS managed 'AWSSupportAccess' role is one simple way of ensuring that this permission is properly granted. To better support the principle of separation of duties, it would be best to only attach this role where necessary.", + "RemediationProcedure": "**From Command Line:** 1. Create an IAM role for managing incidents with AWS: - Create a trust relationship policy document that allows to manage AWS incidents, and save it locally as /tmp/TrustPolicy.json: ``` { Version: 2012-10-17, Statement: [ { Effect: Allow, Principal: { AWS: }, Action: sts:AssumeRole } ] } ``` 2. Create the IAM role using the above trust policy: ``` aws iam create-role --role-name --assume-role-policy-document file:///tmp/TrustPolicy.json ``` 3. Attach 'AWSSupportAccess' managed policy to the created IAM role: ``` aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSSupportAccess --role-name ```", + "AuditProcedure": "**From Command Line:** 1. List IAM policies, filter for the 'AWSSupportAccess' managed policy, and note the Arn element value: ``` aws iam list-policies --query Policies[?PolicyName == 'AWSSupportAccess'] ``` 2. Check if the 'AWSSupportAccess' policy is attached to any role: ``` aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AWSSupportAccess ``` 3. In the output, ensure `PolicyRoles` does not return empty. 'Example: Example: PolicyRoles: [ ]' If it returns empty refer to the remediation below.", + "AdditionalInformation": "AWSSupportAccess policy is a global AWS resource. It has same ARN as `arn:aws:iam::aws:policy/AWSSupportAccess` for every account.", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html:https://aws.amazon.com/premiumsupport/pricing/:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/list-policies.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-role-policy.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/list-entities-for-policy.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.17", + "Description": "Ensure IAM instance roles are used for AWS resource access from instances", + "Checks": [ + "ec2_instance_profile_attached" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. AWS Access means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.", + "RationaleStatement": "AWS IAM roles reduce the risks associated with sharing and rotating credentials that can be used outside of AWS itself. Compromised credentials can be used from outside the AWS account to which they provide access. In contrast, to leverage role permissions, an attacker would need to gain and maintain access to a specific instance to use the privileges associated with it. Additionally, if credentials are encoded into compiled applications or other hard-to-change mechanisms, they are even less likely to be properly rotated due to the risks of service disruption. As time passes, credentials that cannot be rotated are more likely to be known by an increasing number of individuals who no longer work for the organization that owns the credentials.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Sign in to the AWS Management Console and navigate to the EC2 dashboard at `https://console.aws.amazon.com/ec2/`. 2. In the left navigation panel, choose `Instances`. 3. Select the EC2 instance you want to modify. 4. Click `Actions`. 5. Click `Security`. 6. Click `Modify IAM role`. 7. Click `Create new IAM role` if a new IAM role is required. 8. Select the IAM role you want to attach to your instance in the `IAM role` dropdown. 9. Click `Update IAM role`. 10. Repeat steps 3 to 9 for each EC2 instance in your AWS account that requires an IAM role to be attached. **From Command Line:** 1. Run the `describe-instances` command to list all EC2 instance IDs in the selected AWS region: ``` aws ec2 describe-instances --region --query 'Reservations[*].Instances[*].InstanceId' ``` 2. Run the `associate-iam-instance-profile` command to attach an instance profile (which is attached to an IAM role) to the EC2 instance: ``` aws ec2 associate-iam-instance-profile --region --instance-id --iam-instance-profile Name=Instance-Profile-Name ``` 3. Run the `describe-instances` command again for the recently modified EC2 instance. The command output should return the instance profile ARN and ID: ``` aws ec2 describe-instances --region --instance-id --query 'Reservations[*].Instances[*].IamInstanceProfile' ``` 4. Repeat steps 2 and 3 for each EC2 instance in your AWS account that requires an IAM role to be attached.", + "AuditProcedure": "First, check if the instance has any API secrets stored using Secret Scanning. Currently, AWS does not have a solution for this. You can use open-source tools like TruffleHog to scan for secrets in the EC2 instance. If a secret is found, then assign the role to the instance. **From Console:** 1. Sign in to the AWS Management Console and navigate to the EC2 dashboard at `https://console.aws.amazon.com/ec2/`. 2. In the left navigation panel, choose `Instances`. 3. Select the EC2 instance you want to examine. 4. Select `Actions`. 5. Select `View details`. 6. Select `Security` in the lower panel. - If the value for **Instance profile arn** is an instance profile ARN, then an instance profile (that contains an IAM role) is attached. - If the value for **IAM Role** is blank, no role is attached. - If the value for **IAM Role** contains a role, a role is attached. - If the value for **IAM Role** is No roles attached to instance profile: , then an instance profile is attached to the instance, but it does not contain an IAM role. 7. Repeat steps 3 to 6 for each EC2 instance in your AWS account. **From Command Line:** 1. Run the `describe-instances` command to list all EC2 instance IDs in the selected AWS region: ``` aws ec2 describe-instances --region --query 'Reservations[*].Instances[*].InstanceId' ``` 2. Run the `describe-instances` command again for each EC2 instance using the `IamInstanceProfile` identifier in the query filter to check if an IAM role is attached: ``` aws ec2 describe-instances --region --instance-id --query 'Reservations[*].Instances[*].IamInstanceProfile' ``` 3. If an IAM role is attached, the command output will show the IAM instance profile ARN and ID. 4. Repeat steps 2 and 3 for each EC2 instance in your AWS account.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.18", + "Description": "Ensure that all expired SSL/TLS certificates stored in AWS IAM are removed", + "Checks": [ + "iam_no_expired_server_certificates_stored" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use AWS Certificate Manager (ACM) or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.", + "RationaleStatement": "Removing expired SSL/TLS certificates eliminates the risk that an invalid certificate will be deployed accidentally to a resource such as AWS Elastic Load Balancer (ELB), which can damage the credibility of the application/website behind the ELB. As a best practice, it is recommended to delete expired certificates.", + "ImpactStatement": "Deleting the certificate could have implications for your application if you are using an expired server certificate with Elastic Load Balancing, CloudFront, etc. You must make configurations in the respective services to ensure there is no interruption in application functionality.", + "RemediationProcedure": "**From Console:** Removing expired certificates via AWS Management Console is not currently supported. To delete SSL/TLS certificates stored in IAM through the AWS API, use the Command Line Interface (CLI). **From Command Line:** To delete an expired certificate, run the following command by replacing with the name of the certificate to delete: ``` aws iam delete-server-certificate --server-certificate-name ``` When the preceding command is successful, it does not return any output.", + "AuditProcedure": "**From Console:** Getting the certificate expiration information via the AWS Management Console is not currently supported. To request information about the SSL/TLS certificates stored in IAM through the AWS API, use the Command Line Interface (CLI). **From Command Line:** Run the `list-server-certificates` command to list all the IAM-stored server certificates: ``` aws iam list-server-certificates ``` The command output should return an array that contains all the SSL/TLS certificates currently stored in IAM and their metadata (name, ID, expiration date, etc): ``` { ServerCertificateMetadataList: [ { ServerCertificateId: EHDGFRW7EJFYTE88D, ServerCertificateName: MyServerCertificate, Expiration: 2018-07-10T23:59:59Z, Path: /, Arn: arn:aws:iam::012345678910:server-certificate/MySSLCertificate, UploadDate: 2018-06-10T11:56:08Z } ] } ``` Verify the `ServerCertificateName` and `Expiration` parameter value (expiration date) for each SSL/TLS certificate returned by the list-server-certificates command and determine if there are any expired server certificates currently stored in AWS IAM. If so, use the AWS API to remove them. If this command returns: ``` { { ServerCertificateMetadataList: [] } ``` This means that there are no expired certificates; it **does not** mean that no certificates exist.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/delete-server-certificate.html", + "DefaultValue": "By default, expired certificates will not be deleted." + } + ] + }, + { + "Id": "1.19", + "Description": "Ensure that IAM External Access Analyzer is enabled for all regions", + "Checks": [ + "accessanalyzer_enabled" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Enable the IAM External Access Analyzer regarding all resources in each active AWS region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. The results allow you to determine whether an unintended user is permitted, making it easier for administrators to monitor least privilege access. Access Analyzer analyzes only the policies that are applied to resources in the same AWS Region.", + "RationaleStatement": "AWS IAM External Access Analyzer helps you identify the resources in your organization and accounts, such as Amazon S3 buckets or IAM roles, that are shared with external entities. This allows you to identify unintended access to your resources and data. Access Analyzer identifies resources that are shared with external principals by using logic-based reasoning to analyze the resource-based policies in your AWS environment. IAM External Access Analyzer continuously monitors all policies for S3 buckets, IAM roles, KMS (Key Management Service) keys, AWS Lambda functions, Amazon SQS (Simple Queue Service) queues and more", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** Perform the following to enable IAM Access Analyzer for IAM policies: 1. Open the IAM console at `https://console.aws.amazon.com/iam/.` 2. Choose `Access analyzer`. 3. Choose `Create external access analyzer`. 4. On the `Create analyzer` page, confirm that the `Region` displayed is the Region where you want to enable Access Analyzer. 5. Optionally enter a name for the analyzer. 6. Optionally add any tags that you want to apply to the analyzer. 7. Choose `Create Analyzer`. 8. Repeat these step for each active region. **From Command Line:** Run the following command: ``` aws accessanalyzer create-analyzer --analyzer-name --type ``` Repeat this command for each active region. **Note:** The IAM Access Analyzer is successfully configured only when the account you use has the necessary permissions.", + "AuditProcedure": "**From Console:** 1. Open the IAM console at `https://console.aws.amazon.com/iam/` 2. Under `Access analyzer` choose `External Access` 3. Ensure that at least one analyzer is present 4. Ensure that the `STATUS` is set to `Active` 5. Repeat these steps for each active region **From Command Line:** 1. Run the following command: ``` aws accessanalyzer list-analyzers type -- | grep status ``` 2. Ensure that at least one Analyzer's `status` is set to `ACTIVE`. 3. Repeat the steps above for each active region. If an Access Analyzer is not listed for each region or the status is not set to active refer to the remediation procedure below.", + "AdditionalInformation": "Some regions in AWS are enabled by default, while others are disabled by default. Regions introduced prior to March 20, 2019, are enabled by default and cannot be disabled. Regions introduced afterward can be disabled by default. For more information on managing AWS Regions, please see AWS's [documentation on managing AWS Regions](https://docs.aws.amazon.com/general/latest/gr/rande-manage.html).", + "References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/accessanalyzer/get-analyzer.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/accessanalyzer/create-analyzer.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.20", + "Description": "Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments", + "Checks": [ + "iam_check_saml_providers_sts" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.", + "RationaleStatement": "Centralizing IAM user management to a single identity store reduces complexity and thus the likelihood of access management errors.", + "ImpactStatement": "", + "RemediationProcedure": "The remediation procedure will vary based on each individual organization's implementation of identity federation and/or AWS Organizations, with the acceptance criteria that no non-service IAM users and non-root accounts are present outside the account providing centralized IAM user management.", + "AuditProcedure": "For multi-account AWS environments with an external identity provider: 1. Determine the master account for identity federation or IAM user management 2. Login to that account through the AWS Management Console 3. Click `Services` 4. Click `IAM` 5. Click `Identity providers` 6. Verify the configuration For multi-account AWS environments with an external identity provider, as well as for those implementing AWS Organizations without an external identity provider: 1. Determine all accounts that should not have local users present 2. Log into the AWS Management Console 3. Switch role into each identified account 4. Click `Services` 5. Click `IAM` 6. Click `Users` 7. Confirm that no IAM users representing individuals are present", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "" + } + ] + }, + { + "Id": "1.21", + "Description": "Ensure access to AWSCloudShellFullAccess is restricted", + "Checks": [ + "iam_policy_cloudshell_admin_not_attached" + ], + "Attributes": [ + { + "Section": "1 Identity and Access Management", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment, a user has sudo permissions and can access the internet. Therefore, it is feasible to install file transfer software, for example, and move data from CloudShell to external internet servers.", + "RationaleStatement": "Access to this policy should be restricted, as it presents a potential channel for data exfiltration by malicious cloud admins who are given full permissions to the service. AWS documentation describes how to create a more restrictive IAM policy that denies file transfer permissions.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console** 1. Open the IAM console at https://console.aws.amazon.com/iam/ 2. In the left pane, select Policies 3. Search for and select AWSCloudShellFullAccess 4. On the Entities attached tab, for each item, check the box and select Detach", + "AuditProcedure": "**From Console** 1. Open the IAM console at https://console.aws.amazon.com/iam/ 2. In the left pane, select Policies 3. Search for and select AWSCloudShellFullAccess 4. On the Entities attached tab, ensure that there are no entities using this policy **From Command Line** 1. List IAM policies, filter for the 'AWSCloudShellFullAccess' managed policy, and note the Arn element value: ``` aws iam list-policies --query Policies[?PolicyName == 'AWSCloudShellFullAccess'] ``` 2. Check if the 'AWSCloudShellFullAccess' policy is attached to any role: ``` aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AWSCloudShellFullAccess ``` 3. In the output, ensure PolicyRoles returns empty. 'Example: Example: PolicyRoles: [ ]' If it does not return empty, refer to the remediation below. **Note:** Keep in mind that other policies may grant access.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/cloudshell/latest/userguide/sec-auth-with-identities.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.1.1", + "Description": "Ensure S3 Bucket Policy is set to deny HTTP requests", + "Checks": [ + "s3_bucket_secure_transport_policy" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.1 Simple Storage Service (S3)", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy, making the objects accessible only through HTTPS.", + "RationaleStatement": "By default, Amazon S3 allows both HTTP and HTTPS requests. To ensure that access to Amazon S3 objects is only permitted through HTTPS, you must explicitly deny HTTP requests. Bucket policies that allow HTTPS requests without explicitly denying HTTP requests will not comply with this recommendation.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Select the check box next to the Bucket. 3. Click on 'Permissions'. 4. Click 'Bucket Policy'. 5. Add either of the following to the existing policy, filling in the required information: ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: arn:aws:s3:::/*, Condition: { Bool: { aws:SecureTransport: false } } } ``` or ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: [ arn:aws:s3:::, arn:aws:s3:::/* ], Condition: { NumericLessThan: { s3:TlsVersion: 1.2 } } } ``` 6. Save 7. Repeat for all the buckets in your AWS account that contain sensitive data. **From Console** Using AWS Policy Generator: 1. Repeat steps 1-4 above. 2. Click on `Policy Generator` at the bottom of the Bucket Policy Editor. 3. Select Policy Type `S3 Bucket Policy`. 4. Add Statements: - `Effect` = Deny - `Principal` = * - `AWS Service` = Amazon S3 - `Actions` = * - `Amazon Resource Name` = 5. Generate Policy. 6. Copy the text and add it to the Bucket Policy. **From Command Line:** 1. Export the bucket policy to a json file: ``` aws s3api get-bucket-policy --bucket --query Policy --output text > policy.json ``` 2. Modify the policy.json file by adding either of the following: ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: arn:aws:s3:::/*, Condition: { Bool: { aws:SecureTransport: false } } } ``` or ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: [ arn:aws:s3:::, arn:aws:s3:::/* ], Condition: { NumericLessThan: { s3:TlsVersion: 1.2 } } } ``` 3. Apply this modified policy back to the S3 bucket: ``` aws s3api put-bucket-policy --bucket --policy file://policy.json ```", + "AuditProcedure": "To allow access to HTTPS, you can use a bucket policy with the effect `allow` and a condition that checks for the key `aws:SecureTransport: true`. This means that HTTPS requests are allowed, but it does not deny HTTP requests. To explicitly deny HTTP access, ensure that there is also a bucket policy with the effect `deny` that contains the key `aws:SecureTransport: false`. You may also require TLS by setting a policy to deny any version lower than the one you wish to require, using the condition `NumericLessThan` and the key `s3:TlsVersion: 1.2`. **From Console:** 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Select the check box next to the Bucket. 3. Click on 'Permissions', then click on `Bucket Policy`. 4. Ensure that a policy is listed that matches either: ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: arn:aws:s3:::/*, Condition: { Bool: { aws:SecureTransport: false } } } ``` or ``` { Sid: , Effect: Deny, Principal: *, Action: s3:*, Resource: [ arn:aws:s3:::, arn:aws:s3:::/* ], Condition: { NumericLessThan: { s3:TlsVersion: 1.2 } } } ``` `` and `` will be specific to your account, and TLS version will be site/policy specific to your organisation. 5. Repeat for all the buckets in your AWS account. **From Command Line:** 1. List all of the S3 Buckets ``` aws s3 ls ``` 2. Using the list of buckets, run this command on each of them: ``` aws s3api get-bucket-policy --bucket | grep aws:SecureTransport ``` or ``` aws s3api get-bucket-policy --bucket | grep s3:TlsVersion ``` NOTE : If an error is thrown by the CLI, it means no policy has been configured for the specified S3 bucket, and that by default it is allowing both HTTP and HTTPS requests. 3. Confirm that `aws:SecureTransport` is set to false (such as `aws:SecureTransport:false`) or that `s3:TlsVersion` has a site-specific value. 4. Confirm that the policy line has Effect set to Deny 'Effect:Deny'", + "AdditionalInformation": "", + "References": "https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/:https://aws.amazon.com/blogs/security/how-to-use-bucket-policies-and-apply-defense-in-depth-to-help-secure-your-amazon-s3-data/:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/get-bucket-policy.html", + "DefaultValue": "Both HTTP and HTTPS requests are allowed." + } + ] + }, + { + "Id": "2.1.2", + "Description": "Ensure MFA Delete is enabled on S3 buckets", + "Checks": [ + "s3_bucket_no_mfa_delete" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.1 Simple Storage Service (S3)", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket, it requires the user to provide two forms of authentication.", + "RationaleStatement": "Adding MFA delete to an S3 bucket requires additional authentication when you change the version state of your bucket or delete an object version, adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.", + "ImpactStatement": "Enabling MFA delete on an S3 bucket could require additional administrator oversight. Enabling MFA delete may impact other services that automate the creation and/or deletion of S3 buckets.", + "RemediationProcedure": "Perform the steps below to enable MFA delete on an S3 bucket: **Note:** - You cannot enable MFA Delete using the AWS Management Console; you must use the AWS CLI or API. - You must use your 'root' account to enable MFA Delete on S3 buckets. **From Command line:** 1. Run the s3api `put-bucket-versioning` command: ``` aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode” ```", + "AuditProcedure": "Perform the steps below to confirm that MFA delete is configured on an S3 bucket: **From Console:** 1. Login to the S3 console at `https://console.aws.amazon.com/s3/`. 2. Click the `check` box next to the name of the bucket you want to confirm. 3. In the window under `Properties`: - Confirm that Versioning is `Enabled` - Confirm that MFA Delete is `Enabled` **From Command Line:** 1. Run the `get-bucket-versioning` command: ``` aws s3api get-bucket-versioning --bucket my-bucket ``` Example output: ``` Enabled Enabled ``` If the console or CLI output does not show that Versioning and MFA Delete are `enabled`, please refer to the remediation below.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.1.3", + "Description": "Ensure all data in Amazon S3 has been discovered, classified, and secured when necessary", + "Checks": [ + "macie_is_enabled" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.1 Simple Storage Service (S3)", + "Profile": "Level 2", + "AssessmentStatus": "Manual", + "Description": "Amazon S3 buckets can contain sensitive data that, for security purposes, should be discovered, monitored, classified, and protected. Macie, along with other third-party tools, can automatically provide an inventory of Amazon S3 buckets.", + "RationaleStatement": "Using a cloud service or third-party software to continuously monitor and automate the process of data discovery and classification for S3 buckets through machine learning and pattern matching is a strong defense in protecting that information. Amazon Macie is a fully managed data security and privacy service that uses machine learning and pattern matching to discover and protect your sensitive data in AWS.", + "ImpactStatement": "There is a cost associated with using Amazon Macie, and there is typically a cost associated with third-party tools that perform similar processes and provide protection.", + "RemediationProcedure": "Perform the steps below to enable and configure Amazon Macie: **From Console:** 1. Log on to the Macie console at `https://console.aws.amazon.com/macie/`. 2. Click `Get started`. 3. Click `Enable Macie`. Set up a repository for sensitive data discovery results: 1. In the left pane, under Settings, click `Discovery results`. 2. Make sure `Create bucket` is selected. 3. Create a bucket and enter a name for it. The name must be unique across all S3 buckets, and it must start with a lowercase letter or a number. 4. Click `Advanced`. 5. For block all public access, make sure `Yes` is selected. 6. For KMS encryption, specify the AWS KMS key that you want to use to encrypt the results. The key must be a symmetric customer master key (CMK) that is in the same region as the S3 bucket. 7. Click `Save`. Create a job to discover sensitive data: 1. In the left pane, click `S3 buckets`. Macie displays a list of all the S3 buckets for your account. 2. Check the box for each bucket that you want Macie to analyze as part of the job. 3. Click `Create job`. 4. Click `Quick create`. 5. For the Name and Description step, enter a name and, optionally, a description of the job. 6. Click `Next`. 7. For the Review and create step, click `Submit`. Review your findings: 1. In the left pane, click `Findings`. 2. To view the details of a specific finding, choose any field other than the check box for the finding. If you are using a third-party tool to manage and protect your S3 data, follow the vendor documentation for implementing and configuring that tool.", + "AuditProcedure": "Perform the following steps to determine if Macie is running: **From Console:** 1. Login to the Macie console at https://console.aws.amazon.com/macie/. 2. In the left hand pane, click on `By job` under findings. 3. Confirm that you have a job set up for your S3 buckets. When you log into the Macie console, if you are not taken to the summary page and do not have a job set up and running, then refer to the remediation procedure below. If you are using a third-party tool to manage and protect your S3 data, you meet this recommendation.", + "AdditionalInformation": "", + "References": "https://aws.amazon.com/macie/getting-started/:https://docs.aws.amazon.com/workspaces/latest/adminguide/data-protection.html:https://docs.aws.amazon.com/macie/latest/user/data-classification.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.1.4", + "Description": "Ensure that S3 is configured with 'Block Public Access' enabled", + "Checks": [ + "s3_bucket_level_public_access_block", + "s3_account_level_public_access_blocks" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.1 Simple Storage Service (S3)", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket and its contained objects from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets and their contained objects from becoming publicly accessible across the entire account.", + "RationaleStatement": "Amazon S3 `Block public access (bucket settings)` prevents the accidental or malicious public exposure of data contained within the respective bucket(s). Amazon S3 `Block public access (account settings)` prevents the accidental or malicious public exposure of data contained within all buckets of the respective AWS account. Whether to block public access to all or some buckets is an organizational decision that should be based on data sensitivity, least privilege, and use case.", + "ImpactStatement": "When you apply Block Public Access settings to an account, the settings apply to all AWS regions globally. The settings may not take effect in all regions immediately or simultaneously, but they will eventually propagate to all regions.", + "RemediationProcedure": "**If utilizing Block Public Access (bucket settings)** **From Console:** 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Select the check box next to a bucket. 3. Click 'Edit public access settings'. 4. Click 'Block all public access' 5. Repeat for all the buckets in your AWS account that contain sensitive data. **From Command Line:** 1. List all of the S3 buckets: ``` aws s3 ls ``` 2. Enable Block Public Access on a specific bucket: ``` aws s3api put-public-access-block --bucket --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true ``` **If utilizing Block Public Access (account settings)** **From Console:** If the output reads `true` for the separate configuration settings, then Block Public Access is enabled on the account. 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Click `Block Public Access (account settings)`. 3. Click `Edit` to change the block public access settings for all the buckets in your AWS account. 4. Update the settings and click `Save`. For details about each setting, pause on the `i` icons. 5. When you're asked for confirmation, enter `confirm`. Then click `Confirm` to save your changes. **From Command Line:** To enable Block Public Access for this account, run the following command: ``` aws s3control put-public-access-block --public-access-block-configuration BlockPublicAcls=true, IgnorePublicAcls=true, BlockPublicPolicy=true, RestrictPublicBuckets=true --account-id ```", + "AuditProcedure": "**If utilizing Block Public Access (bucket settings)** **From Console:** 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Select the check box next to a bucket. 3. Click on 'Edit public access settings'. 4. Ensure that the block public access settings are configured appropriately for this bucket. 5. Repeat for all the buckets in your AWS account. **From Command Line:** 1. List all of the S3 buckets: ``` aws s3 ls ``` 2. Find the public access settings for a specific bucket: ``` aws s3api get-public-access-block --bucket ``` Output if Block Public Access is enabled: ``` { PublicAccessBlockConfiguration: { BlockPublicAcls: true, IgnorePublicAcls: true, BlockPublicPolicy: true, RestrictPublicBuckets: true } } ``` If the output reads `false` for the separate configuration settings, then proceed with the remediation. **If utilizing Block Public Access (account settings)** **From Console:** 1. Login to the AWS Management Console and open the Amazon S3 console using https://console.aws.amazon.com/s3/. 2. Choose `Block public access (account settings)`. 3. Ensure that the block public access settings are configured appropriately for your AWS account. **From Command Line:** To check the block public access settings for this account, run the following command: `aws s3control get-public-access-block --account-id --region ` Output if Block Public Access is enabled: ``` { PublicAccessBlockConfiguration: { IgnorePublicAcls: true, BlockPublicPolicy: true, BlockPublicAcls: true, RestrictPublicBuckets: true } } ``` If the output reads `false` for the separate configuration settings, then proceed with the remediation.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonS3/latest/user-guide/block-public-access-account.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.2.1", + "Description": "Ensure that encryption-at-rest is enabled for RDS instances", + "Checks": [ + "rds_instance_storage_encrypted" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.2 Relational Database Service (RDS)", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Amazon RDS encrypted DB instances use the industry-standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles the authentication of access and the decryption of your data transparently, with minimal impact on performance.", + "RationaleStatement": "Databases are likely to hold sensitive and critical data; therefore, it is highly recommended to implement encryption to protect your data from unauthorized access or disclosure. With RDS encryption enabled, the data stored on the instance's underlying storage, the automated backups, read replicas, and snapshots are all encrypted.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and open the RDS dashboard at https://console.aws.amazon.com/rds/. 2. In the left navigation panel, click on `Databases`. 3. Select the Database instance that needs to be encrypted. 4. Click the `Actions` button placed at the top right and select `Take Snapshot`. 5. On the Take Snapshot page, enter the name of the database for which you want to take a snapshot in the `Snapshot Name` field and click on `Take Snapshot`. 6. Select the newly created snapshot, click the `Action` button placed at the top right, and select `Copy snapshot` from the Action menu. 7. On the Make Copy of DB Snapshot page, perform the following: - In the `New DB Snapshot Identifier` field, enter a name for the new snapshot. - Check `Copy Tags`. The new snapshot must have the same tags as the source snapshot. - Select `Yes` from the `Enable Encryption` dropdown list to enable encryption. You can choose to use the AWS default encryption key or a custom key from the Master Key dropdown list. 8. Click `Copy Snapshot` to create an encrypted copy of the selected instance's snapshot. 9. Select the new Snapshot Encrypted Copy and click the `Action` button located at the top right. Then, select the `Restore Snapshot` option from the Action menu. This will restore the encrypted snapshot to a new database instance. 10. On the Restore DB Instance page, enter a unique name for the new database instance in the DB Instance Identifier field. 11. Review the instance configuration details and click `Restore DB Instance`. 12. As the new instance provisioning process is completed, you can update the application configuration to refer to the endpoint of the new encrypted database instance. Once the database endpoint is changed at the application level, you can remove the unencrypted instance. **From Command Line:** 1. Run the `describe-db-instances` command to list the names of all RDS database instances in the selected AWS region. The command output should return database instance identifiers: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. Run the `create-db-snapshot` command to create a snapshot for a selected database instance. The command output will return the `new snapshot` with name DB Snapshot Name: ``` aws rds create-db-snapshot --region --db-snapshot-identifier --db-instance-identifier ``` 3. Now run the `list-aliases` command to list the KMS key aliases available in a specified region. The command output should return each `key alias currently available`. For our RDS encryption activation process, locate the ID of the AWS default KMS key: ``` aws kms list-aliases --region ``` 4. Run the `copy-db-snapshot` command using the default KMS key ID for the RDS instances returned earlier to create an encrypted copy of the database instance snapshot. The command output will return the `encrypted instance snapshot configuration`: ``` aws rds copy-db-snapshot --region --source-db-snapshot-identifier --target-db-snapshot-identifier --copy-tags --kms-key-id ``` 5. Run the `restore-db-instance-from-db-snapshot` command to restore the encrypted snapshot created in the previous step to a new database instance. If successful, the command output should return the configuration of the new encrypted database instance: ``` aws rds restore-db-instance-from-db-snapshot --region --db-instance-identifier --db-snapshot-identifier ``` 6. Run the `describe-db-instances` command to list all RDS database names available in the selected AWS region. The output will return the database instance identifier names. Select the encrypted database name that we just created, `db-name-encrypted`: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 7. Run the `describe-db-instances` command again using the RDS instance identifier returned earlier to determine if the selected database instance is encrypted. The command output should indicate that the encryption status is `True`: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].StorageEncrypted' ```", + "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and open the RDS dashboard at https://console.aws.amazon.com/rds/. 2. In the navigation pane, under RDS dashboard, click `Databases`. 3. Select the RDS instance that you want to examine. 4. Click `Instance Name` to see details, then select the `Configuration` tab. 5. Under Configuration Details, in the Storage pane, search for the `Encryption Enabled` status. 6. If the current status is set to `Disabled`, encryption is not enabled for the selected RDS database instance. 7. Repeat steps 2 to 6 to verify the encryption status of other RDS instances in the same region. 8. Change the region from the top of the navigation bar, and repeat the audit steps for other regions. **From Command Line:** 1. Run the `describe-db-instances` command to list all the RDS database instance names available in the selected AWS region. The output will return each database instance identifier (name): ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. Run the `describe-db-instances` command again, using an RDS instance identifier returned from step 1, to determine if the selected database instance is encrypted. The output should return the encryption status `True` or `False`: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].StorageEncrypted' ``` 3. If the StorageEncrypted parameter value is `False`, encryption is not enabled for the selected RDS database instance. 4. Repeat steps 1 to 3 to audit each RDS instance, and change the region to verify RDS instances in other regions.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html:https://aws.amazon.com/blogs/database/selecting-the-right-encryption-options-for-amazon-rds-and-amazon-aurora-database-engines/#:~:text=With%20RDS%2Dencrypted%20resources%2C%20data,transparent%20to%20your%20database%20engine.:https://aws.amazon.com/rds/features/security/", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.2.2", + "Description": "Ensure the Auto Minor Version Upgrade feature is enabled for RDS instances", + "Checks": [ + "rds_instance_minor_version_upgrade_enabled" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.2 Relational Database Service (RDS)", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled to automatically receive minor engine upgrades during the specified maintenance window. This way, RDS instances can obtain new features, bug fixes, and security patches for their database engines.", + "RationaleStatement": "AWS RDS will occasionally deprecate minor engine versions and provide new ones for upgrades. When the last version number within a release is replaced, the changed version is considered minor. With the Auto Minor Version Upgrade feature enabled, version upgrades will occur automatically during the specified maintenance window, allowing your RDS instances to receive new features, bug fixes, and security patches for their database engines.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Log in to the AWS management console and navigate to the RDS dashboard at https://console.aws.amazon.com/rds/. 2. In the left navigation panel, click `Databases`. 3. Select the RDS instance that you want to update. 4. Click on the `Modify` button located at the top right side. 5. On the `Modify DB Instance: ` page, In the `Maintenance` section, select `Auto minor version upgrade` and click the `Yes` radio button. 6. At the bottom of the page, click `Continue`, and check `Apply Immediately` to apply the changes immediately, or select `Apply during the next scheduled maintenance window` to avoid any downtime. 7. Review the changes and click `Modify DB Instance`. The instance status should change from available to modifying and back to available. Once the feature is enabled, the `Auto Minor Version Upgrade` status should change to `Yes`. **From Command Line:** 1. Run the `describe-db-instances` command to list all RDS database instance names available in the selected AWS region: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. The command output should return each database instance identifier. 3. Run the `modify-db-instance` command to modify the configuration of a selected RDS instance. This command will apply the changes immediately. Remove `--apply-immediately` to apply changes during the next scheduled maintenance window and avoid any downtime: ``` aws rds modify-db-instance --region --db-instance-identifier --auto-minor-version-upgrade --apply-immediately ``` 4. The command output should reveal the new configuration metadata for the RDS instance, including the `AutoMinorVersionUpgrade` parameter value. 5. Run the `describe-db-instances` command to check if the Auto Minor Version Upgrade feature has been successfully enabled: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].AutoMinorVersionUpgrade' ``` 6. The command output should return the feature's current status set to `true`, indicating that the feature is `enabled`, and that the minor engine upgrades will be applied to the selected RDS instance.", + "AuditProcedure": "**From Console:** 1. Log in to the AWS management console and navigate to the RDS dashboard at https://console.aws.amazon.com/rds/. 2. In the left navigation panel, click `Databases`. 3. Select the RDS instance that you want to examine. 4. Click on the `Maintenance and backups` panel. 5. Under the `Maintenance` section, search for the Auto Minor Version Upgrade status. - If the current status is `Disabled`, it means that the feature is not enabled, and the minor engine upgrades released will not be applied to the selected RDS instance. **From Command Line:** 1. Run the `describe-db-instances` command to list all RDS database names available in the selected AWS region: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. The command output should return each database instance identifier. 3. Run the `describe-db-instances` command again using a RDS instance identifier returned earlier to determine the Auto Minor Version Upgrade status for the selected instance: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].AutoMinorVersionUpgrade' ``` 4. The command output should return the current status of the feature. If the current status is set to `true`, the feature is enabled and the minor engine upgrades will be applied to the selected RDS instance.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_RDS_Managing.html:https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Upgrading.html:https://aws.amazon.com/rds/faqs/", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.2.3", + "Description": "Ensure that RDS instances are not publicly accessible", + "Checks": [ + "rds_instance_no_public_access" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.2 Relational Database Service (RDS)", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Ensure and verify that the RDS database instances provisioned in your AWS account restrict unauthorized access in order to minimize security risks. To restrict access to any RDS database instance, you must disable the Publicly Accessible flag for the database and update the VPC security group associated with the instance.", + "RationaleStatement": "Ensure that no public-facing RDS database instances are provisioned in your AWS account, and restrict unauthorized access in order to minimize security risks. When the RDS instance allows unrestricted access (0.0.0.0/0), anyone and anything on the Internet can establish a connection to your database, which can increase the opportunity for malicious activities such as brute force attacks, PostgreSQL injections, or DoS/DDoS attacks.", + "ImpactStatement": "", + "RemediationProcedure": "**From Console:** 1. Log in to the AWS management console and navigate to the RDS dashboard at https://console.aws.amazon.com/rds/. 2. Under the navigation panel, on the RDS dashboard, click `Databases`. 3. Select the RDS instance that you want to update. 4. Click `Modify` from the dashboard top menu. 5. On the Modify DB Instance panel, under the `Connectivity` section, click on `Additional connectivity configuration` and update the value for `Publicly Accessible` to `Not publicly accessible` to restrict public access. 6. Follow the below steps to update subnet configurations: - Select the `Connectivity and security` tab, and click the VPC attribute value inside the `Networking` section. - Select the `Details` tab from the VPC dashboard's bottom panel and click the Route table configuration attribute value. - On the Route table details page, select the Routes tab from the dashboard's bottom panel and click `Edit routes`. - On the Edit routes page, update the Destination of Target which is set to `igw-xxxxx` and click `Save` routes. 7. On the Modify DB Instance panel, click `Continue`, and in the Scheduling of modifications section, perform one of the following actions based on your requirements: - Select `Apply during the next scheduled maintenance window` to apply the changes automatically during the next scheduled maintenance window. - Select `Apply immediately` to apply the changes right away. With this option, any pending modifications will be asynchronously applied as soon as possible, regardless of the maintenance window setting for this RDS database instance. Note that any changes available in the pending modifications queue are also applied. If any of the pending modifications require downtime, choosing this option can cause unexpected downtime for the application. 8. Repeat steps 3-7 for each RDS instance in the current region. 9. Change the AWS region from the navigation bar to repeat the process for other regions. **From Command Line:** 1. Run the `describe-db-instances` command to list all available RDS database identifiers in the selected AWS region: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. The command output should return each database instance identifier. 3. Run the `modify-db-instance` command to modify the configuration of a selected RDS instance, disabling the `Publicly Accessible` flag for that instance. This command uses the `apply-immediately` flag. If you want to avoid any downtime, the `--no-apply-immediately` flag can be used: ``` aws rds modify-db-instance --region --db-instance-identifier --no-publicly-accessible --apply-immediately ``` 4. The command output should reveal the `PubliclyAccessible` configuration under pending values, to be applied at the specified time. 5. Updating the Internet Gateway destination via the AWS CLI is not currently supported. To update information about the Internet Gateway, please use the AWS Console procedure. 6. Repeat steps 1-5 for each RDS instance provisioned in the current region. 7. Change the AWS region by using the --region filter to repeat the process for other regions.", + "AuditProcedure": "**From Console:** 1. Log in to the AWS management console and navigate to the RDS dashboard at https://console.aws.amazon.com/rds/. 2. Under the navigation panel, on the RDS dashboard, click `Databases`. 3. Select the RDS instance that you want to examine. 4. Click `Instance Name` from the dashboard, under `Connectivity and Security`. 5. In the `Security` section, check if the Publicly Accessible flag status is set to `Yes`. 6. Follow the steps below to check database subnet access: - In the `networking` section, click the subnet link under `Subnets`. - The link will redirect you to the VPC Subnets page. - Select the subnet listed on the page and click the `Route Table` tab from the dashboard bottom panel. - If the route table contains any entries with the destination CIDR block set to `0.0.0.0/0` and an `Internet Gateway` attached, the selected RDS database instance was provisioned inside a public subnet; therefore, it is not running within a logically isolated environment and can be accessed from the Internet. 7. Repeat steps 3-6 to determine the configuration of other RDS database instances provisioned in the current region. 8. Change the AWS region from the navigation bar and repeat the audit process for other regions. **From Command Line:** 1. Run the `describe-db-instances` command to list all available RDS database names in the selected AWS region: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. The command output should return each database instance `identifier`. 3. Run the `describe-db-instances` command again, using the `PubliclyAccessible` parameter as a query filter to reveal the status of the database instance's Publicly Accessible flag: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].PubliclyAccessible' ``` 4. Check the Publicly Accessible parameter status. If the Publicly Accessible flag is set to `Yes`, then the selected RDS database instance is publicly accessible and insecure. Follow the steps mentioned below to check database subnet access. 5. Run the `describe-db-instances` command again using the RDS database instance identifier that you want to check, along with the appropriate filtering to describe the VPC subnet(s) associated with the selected instance: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].DBSubnetGroup.Subnets[]' ``` - The command output should list the subnets available in the selected database subnet group. 6. Run the `describe-route-tables` command using the ID of the subnet returned in the previous step to describe the routes of the VPC route table associated with the selected subnet: ``` aws ec2 describe-route-tables --region --filters Name=association.subnet-id,Values= --query 'RouteTables[*].Routes[]' ``` - If the command returns the route table associated with the database instance subnet ID, check the values of the `GatewayId` and `DestinationCidrBlock` attributes returned in the output. If the route table contains any entries with the `GatewayId` value set to `igw-xxxxxxxx` and the `DestinationCidrBlock` value set to `0.0.0.0/0`, the selected RDS database instance was provisioned within a public subnet. - Or, if the command returns empty results, the route table is implicitly associated with the subnet; therefore, the audit process continues with the next step. 7. Run the `describe-db-instances` command again using the RDS database instance identifier that you want to check, along with the appropriate filtering to describe the VPC ID associated with the selected instance: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].DBSubnetGroup.VpcId' ``` - The command output should show the VPC ID in the selected database subnet group. 8. Now run the `describe-route-tables` command using the ID of the VPC returned in the previous step to describe the routes of the VPC's main route table that is implicitly associated with the selected subnet: ``` aws ec2 describe-route-tables --region --filters Name=vpc-id,Values= Name=association.main,Values=true --query 'RouteTables[*].Routes[]' ``` - The command output returns the VPC main route table implicitly associated with the database instance subnet ID. Check the values of the `GatewayId` and `DestinationCidrBlock` attributes returned in the output. If the route table contains any entries with the `GatewayId` value set to `igw-xxxxxxxx` and the `DestinationCidrBlock` value set to `0.0.0.0/0`, the selected RDS database instance was provisioned inside a public subnet; therefore, it is not running within a logically isolated environment and does not adhere to AWS security best practices.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.html:https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html:https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html:https://aws.amazon.com/rds/faqs/", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.2.4", + "Description": "Ensure Multi-AZ deployments are used for enhanced availability in Amazon RDS", + "Checks": [ + "rds_cluster_multi_az", + "rds_instance_multi_az" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.2 Relational Database Service (RDS)", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Amazon RDS offers Multi-AZ deployments that provide enhanced availability and durability for your databases, using synchronous replication to replicate data to a standby instance in a different Availability Zone (AZ). In the event of an infrastructure failure, Amazon RDS automatically fails over to the standby to minimize downtime and ensure business continuity.", + "RationaleStatement": "Database availability is crucial for maintaining service uptime, particularly for applications that are critical to the business. Implementing Multi-AZ deployments with Amazon RDS ensures that your databases are protected against unplanned outages due to hardware failures, network issues, or other disruptions. This configuration enhances both the availability and durability of your database, making it a highly recommended practice for production environments.", + "ImpactStatement": "Multi-AZ deployments may increase costs due to the additional resources required to maintain a standby instance; however, the benefits of increased availability and reduced risk of downtime outweigh these costs for critical applications.", + "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and open the RDS dashboard at [AWS RDS Console](https://console.aws.amazon.com/rds/). 2. In the left navigation pane, click on `Databases`. 3. Select the database instance that needs Multi-AZ deployment to be enabled. 4. Click the `Modify` button at the top right. 5. Scroll down to the `Availability & Durability` section. 6. Under `Multi-AZ deployment`, select `Yes` to enable. 7. Review the changes and click `Continue`. 8. On the `Review` page, choose `Apply immediately` to make the change without waiting for the next maintenance window, or `Apply during the next scheduled maintenance window`. 9. Click `Modify DB Instance` to apply the changes. **From Command Line:** 1. Run the following command to modify the RDS instance and enable Multi-AZ: ``` aws rds modify-db-instance --region --db-instance-identifier --multi-az --apply-immediately ``` 2. Confirm that the Multi-AZ deployment is enabled by running the following command: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].MultiAZ' ``` - The output should return `True`, indicating that Multi-AZ is enabled. 3. Repeat the procedure for other instances as necessary.", + "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and open the RDS dashboard at [AWS RDS Console](https://console.aws.amazon.com/rds/). 2. In the navigation pane, under `Databases`, select the RDS instance you want to examine. 3. Click the `Instance Name` to see details, then navigate to the `Configuration` tab. 4. Under the `Availability & Durability` section, check the `Multi-AZ` status. - If Multi-AZ deployment is enabled, it will display `Yes`. - If it is disabled, the status will display `No`. 5. Repeat steps 2-4 to verify the Multi-AZ status of other RDS instances in the same region. 6. Change the region from the top of the navigation bar and repeat the audit for other regions. **From Command Line:** 1. Run the following command to list all RDS instances in the selected AWS region: ``` aws rds describe-db-instances --region --query 'DBInstances[*].DBInstanceIdentifier' ``` 2. Run the following command using the instance identifier returned earlier to check the Multi-AZ status: ``` aws rds describe-db-instances --region --db-instance-identifier --query 'DBInstances[*].MultiAZ' ``` - If the output is `True`, Multi-AZ is enabled. - If the output is `False`, Multi-AZ is not enabled. 3. Repeat steps 1 and 2 to audit each RDS instance, and change regions to verify in other regions.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "" + } + ] + }, + { + "Id": "2.3.1", + "Description": "Ensure that encryption is enabled for EFS file systems", + "Checks": [ + "efs_encryption_at_rest_enabled" + ], + "Attributes": [ + { + "Section": "2 Storage", + "SubSection": "2.3 Elastic File System (EFS)", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "EFS data should be encrypted at rest using AWS KMS (Key Management Service).", + "RationaleStatement": "Data should be encrypted at rest to reduce the risk of a data breach via direct access to the storage device.", + "ImpactStatement": "", + "RemediationProcedure": "**It is important to note that EFS file system data-at-rest encryption must be turned on when creating the file system. If an EFS file system has been created without data-at-rest encryption enabled, then you must create another EFS file system with the correct configuration and transfer the data.** **Steps to create an EFS file system with data encrypted at rest:** **From Console:** 1. Login to the AWS Management Console and Navigate to the `Elastic File System (EFS)` dashboard. 2. Select `File Systems` from the left navigation panel. 3. Click the `Create File System` button from the dashboard top menu to start the file system setup process. 4. On the `Configure file system access` configuration page, perform the following actions: - Choose an appropriate VPC from the VPC dropdown list. - Within the `Create mount targets` section, check the boxes for all of the Availability Zones (AZs) within the selected VPC. These will be your mount targets. - Click `Next step` to continue. 5. Perform the following on the `Configure optional settings` page: - Create `tags` to describe your new file system. - Choose `performance mode` based on your requirements. - Check the `Enable encryption` box and choose `aws/elasticfilesystem` from the `Select KMS master key` dropdown list to enable encryption for the new file system, using the default master key provided and managed by AWS KMS. - Click `Next step` to continue. 6. Review the file system configuration details on the `review and create` page and then click `Create File System` to create your new AWS EFS file system. 7. Copy the data from the old unencrypted EFS file system onto the newly created encrypted file system. 8. Remove the unencrypted file system as soon as your data migration to the newly created encrypted file system is completed. 9. Change the AWS region from the navigation bar and repeat the entire process for the other AWS regions. **From CLI:** 1. Run the `describe-file-systems` command to view the configuration information for the selected unencrypted file system identified in the Audit steps: ``` aws efs describe-file-systems --region --file-system-id ``` 2. The command output should return the configuration information. 3. To provision a new AWS EFS file system, you need to generate a universally unique identifier (UUID) to create the token required by the `create-file-system` command. To create the required token, you can use a randomly generated UUID from https://www.uuidgenerator.net. 4. Run the `create-file-system` command using the unique token created at the previous step: ``` aws efs create-file-system --region --creation-token --performance-mode generalPurpose --encrypted ``` 5. The command output should return the new file system configuration metadata. 6. Run the `create-mount-target` command using the EFS file system ID returned from step 4 as the identifier and the ID of the Availability Zone (AZ) that will represent the mount target: ``` aws efs create-mount-target --region --file-system-id --subnet-id ``` 7. The command output should return the new mount target metadata. 8. Now you can mount your file system from an EC2 instance. 9. Copy the data from the old unencrypted EFS file system to the newly created encrypted file system. 10. Remove the unencrypted file system as soon as your data migration to the newly created encrypted file system is completed: ``` aws efs delete-file-system --region --file-system-id ``` 11. Change the AWS region by updating the --region and repeat the entire process for the other AWS regions.", + "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and Navigate to the Elastic File System (EFS) dashboard. 2. Select `File Systems` from the left navigation panel. 3. Each item on the list has a visible Encrypted field that displays data at rest encryption status. 4. Validate that this field reads `Encrypted` for all EFS file systems in all AWS regions. **From CLI:** 1. Run the `describe-file-systems` command using custom query filters to list the identifiers of all AWS EFS file systems currently available within the selected region: ``` aws efs describe-file-systems --region --output table --query 'FileSystems[*].FileSystemId' ``` 2. The command output should return a table with the requested file system IDs. 3. Run the `describe-file-systems` command using the ID of the file system that you want to examine as `file-system-id` and the necessary query filters: ``` aws efs describe-file-systems --region --file-system-id --query 'FileSystems[*].Encrypted' ``` 4. The command output should return the file system encryption status as `true` or `false`. If the returned value is `false`, the selected AWS EFS file system is not encrypted and if the returned value is `true`, the selected AWS EFS file system is encrypted.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/efs/latest/ug/encryption-at-rest.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/efs/index.html#efs", + "DefaultValue": "EFS file system data is encrypted at rest by default when creating a file system through the Console. However, encryption at rest is not enabled by default when creating a new file system using the AWS CLI, API, or SDKs." + } + ] + }, + { + "Id": "3.1", + "Description": "Ensure CloudTrail is enabled in all regions", + "Checks": [ + "cloudtrail_multi_region_enabled" + ], + "Attributes": [ + { + "Section": "3 Logging", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).", + "RationaleStatement": "The AWS API call history produced by CloudTrail enables security analysis, resource change tracking, and compliance auditing. Additionally, - ensuring that a multi-region trail exists will help detect unexpected activity occurring in otherwise unused regions - ensuring that a multi-region trail exists will ensure that `Global Service Logging` is enabled for a trail by default to capture recordings of events generated on AWS global services - for a multi-region trail, ensuring that management events are configured for all types of Read/Writes ensures the recording of management operations that are performed on all resources in an AWS account", + "ImpactStatement": "S3 lifecycle features can be used to manage the accumulation and management of logs over time. See the following AWS resource for more information on these features: 1. https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html", + "RemediationProcedure": "Perform the following to enable global (Multi-region) CloudTrail logging: **From Console:** 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail). 2. Click on `Trails` in the left navigation pane. 3. Click `Get Started Now` if it is presented, then: - Click `Add new trail`. - Enter a trail name in the `Trail name` box. - A trail created in the console is a multi-region trail by default. - Specify an S3 bucket name in the `S3 bucket` box. - Specify the AWS KMS alias under the `Log file SSE-KMS encryption` section, or create a new key. - Click `Next`. 4. Ensure the `Management events` check box is selected. 5. Ensure both `Read` and `Write` are checked under API activity. 6. Click `Next`. 7. Review your trail settings and click `Create trail`. **From Command Line:** Create a multi-region trail: ``` aws cloudtrail create-trail --name --bucket-name --is-multi-region-trail ``` Enable multi-region on an existing trail: ``` aws cloudtrail update-trail --name --is-multi-region-trail ``` **Note:** Creating a CloudTrail trail via the CLI without providing any overriding options configures all `read` and `write` `Management Events` to be logged by default.", + "AuditProcedure": "Perform the following to determine if CloudTrail is enabled for all regions: **From Console:** 1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. Click on `Trails` in the left navigation pane - You will be presented with a list of trails across all regions 3. Ensure that at least one Trail has `Yes` specified in the `Multi-region trail` column 4. Click on a trail via the link in the `Name` column 5. Ensure `Logging` is set to `ON` 6. Ensure `Multi-region trail` is set to `Yes` 7. In the section `Management Events`, ensure that `API activity` set to `ALL` **From Command Line:** 1. List all trails: ``` aws cloudtrail describe-trails ``` 2. Ensure `IsMultiRegionTrail` is set to `true`: ``` aws cloudtrail get-trail-status --name ``` 3. Ensure `IsLogging` is set to `true`: ``` aws cloudtrail get-event-selectors --trail-name ``` 4. Ensure there is at least one `fieldSelector` for a trail that equals `Management`: - This should NOT output any results for Field: readOnly. If either `true` or `false` is returned, one of the checkboxes (`read` or `write`) is not selected. Example of correct output: ``` TrailARN: , AdvancedEventSelectors: [ { Name: Management events selector, FieldSelectors: [ { Field: eventCategory, Equals: [ Management ] ```", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-concepts.html#cloudtrail-concepts-management-events:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-and-data-events-with-cloudtrail.html?icmpid=docs_cloudtrail_console#logging-management-events:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-supported-services.html#cloud-trail-supported-services-data-events", + "DefaultValue": "Not Enabled" + } + ] + }, + { + "Id": "3.2", + "Description": "Ensure CloudTrail log file validation is enabled", + "Checks": [ + "cloudtrail_log_file_validation_enabled" + ], + "Attributes": [ + { + "Section": "3 Logging", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or remained unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled for all CloudTrails.", + "RationaleStatement": "Enabling log file validation will provide additional integrity checks for CloudTrail logs.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to enable log file validation on a given trail: **From Console:** 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail). 2. Click on `Trails` in the left navigation pane. 3. Click on the target trail. 4. Within the `General details` section, click `edit`. 5. Under `Advanced settings`, check the `enable` box under `Log file validation`. 6. Click `Save changes`. **From Command Line:** Enable log file validation on a trail: ``` aws cloudtrail update-trail --name --enable-log-file-validation ``` Note that periodic validation of logs using these digests can be carried out by running the following command: ``` aws cloudtrail validate-logs --trail-arn --start-time --end-time ```", + "AuditProcedure": "Perform the following on each trail to determine if log file validation is enabled: **From Console:** 1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail). 2. Click on `Trails` in the left navigation pane. 3. For every trail: - Click on a trail via the link in the `Name` column. - Under the `General details` section, ensure `Log file validation` is set to `Enabled`. **From Command Line:** List all trails: ``` aws cloudtrail describe-trails ``` Ensure `LogFileValidationEnabled` is set to `true` for each trail.", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-enabling.html", + "DefaultValue": "Not Enabled" + } + ] + }, + { + "Id": "3.3", + "Description": "Ensure AWS Config is enabled in all regions", + "Checks": [ + "config_recorder_all_regions_enabled" + ], + "Attributes": [ + { + "Section": "3 Logging", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration items (AWS resources), relationships between configuration items (AWS resources), and any configuration changes between resources. It is recommended that AWS Config be enabled in all regions.", + "RationaleStatement": "The AWS configuration item history captured by AWS Config enables security analysis, resource change tracking, and compliance auditing.", + "ImpactStatement": "Enabling AWS Config in all regions provides comprehensive visibility into resource configurations, enhancing security and compliance monitoring. However, this may incur additional costs and require proper configuration management.", + "RemediationProcedure": "To implement AWS Config configuration: **From Console:** 1. Select the region you want to focus on in the top right of the console. 2. Click `Services`. 3. Click `Config`. 4. If a Config Recorder is enabled in this region, navigate to the Settings page from the navigation menu on the left-hand side. If a Config Recorder is not yet enabled in this region, select Get Started. 5. Select Record all resources supported in this region. 6. Choose to include global resources (IAM resources). 7. Specify an S3 bucket in the same account or in another managed AWS account. 8. Create an SNS Topic from the same AWS account or another managed AWS account. **From Command Line:** 1. Ensure there is an appropriate S3 bucket, SNS topic, and IAM role per the [AWS Config Service prerequisites](http://docs.aws.amazon.com/config/latest/developerguide/gs-cli-prereq.html). 2. Run this command to create a new configuration recorder: ``` aws configservice put-configuration-recorder --configuration-recorder name=,roleARN=arn:aws:iam:::role/ --recording-group allSupported=true,includeGlobalResourceTypes=true ``` 3. Create a delivery channel configuration file locally which specifies the channel attributes, populated from the prerequisites set up previously: ``` { name: , s3BucketName: , snsTopicARN: arn:aws:sns:::, configSnapshotDeliveryProperties: { deliveryFrequency: Twelve_Hours } } ``` 4. Run this command to create a new delivery channel, referencing the json configuration file made in the previous step: ``` aws configservice put-delivery-channel --delivery-channel file://.json ``` 5. Start the configuration recorder by running the following command: ``` aws configservice start-configuration-recorder --configuration-recorder-name ```", + "AuditProcedure": "Process to evaluate AWS Config configuration per region: **From Console:** 1. Sign in to the AWS Management Console and open the AWS Config console at [https://console.aws.amazon.com/config/](https://console.aws.amazon.com/config/). 1. On the top right of the console select the target region. 1. If a Config Recorder is enabled in this region, you should navigate to the Settings page from the navigation menu on the left-hand side. If a Config Recorder is not yet enabled in this region, proceed to the remediation steps. 1. Ensure Record all resources supported in this region is checked. 1. Ensure Include global resources (e.g., AWS IAM resources) is checked, unless it is enabled in another region (this is only required in one region). 1. Ensure the correct S3 bucket has been defined. 1. Ensure the correct SNS topic has been defined. 1. Repeat steps 2 to 7 for each region. **From Command Line:** 1. Run this command to show all AWS Config Recorders and their properties: ``` aws configservice describe-configuration-recorders ``` 2. Evaluate the output to ensure that all recorders have a `recordingGroup` object which includes `allSupported: true`. Additionally, ensure that at least one recorder has `includeGlobalResourceTypes: true`. **Note:** There is one more parameter, ResourceTypes, in the recordingGroup object. We don't need to check it, as whenever we set allSupported to true, AWS enforces the resource types to be empty (ResourceTypes: []). Sample output: ``` { ConfigurationRecorders: [ { recordingGroup: { allSupported: true, resourceTypes: [], includeGlobalResourceTypes: true }, roleARN: arn:aws:iam:::role/service-role/, name: default } ] } ``` 3. Run this command to show the status for all AWS Config Recorders: ``` aws configservice describe-configuration-recorder-status ``` 4. In the output, find recorders with `name` key matching the recorders that were evaluated in step 2. Ensure that they include `recording: true` and `lastStatus: SUCCESS`.", + "AdditionalInformation": "", + "References": "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/configservice/describe-configuration-recorder-status.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/configservice/describe-configuration-recorders.html:https://docs.aws.amazon.com/config/latest/developerguide/gs-cli-prereq.html", + "DefaultValue": "" + } + ] + }, + { + "Id": "3.4", + "Description": "Ensure that server access logging is enabled on the CloudTrail S3 bucket", + "Checks": [ + "cloudtrail_logs_s3_bucket_access_logging_enabled" + ], + "Attributes": [ + { + "Section": "3 Logging", + "Profile": "Level 1", + "AssessmentStatus": "Manual", + "Description": "Server access logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that server access logging be enabled on the CloudTrail S3 bucket.", + "RationaleStatement": "By enabling server access logging on target S3 buckets, it is possible to capture all events that may affect objects within any target bucket. Configuring the logs to be placed in a separate bucket allows access to log information that can be useful in security and incident response workflows.", + "ImpactStatement": "", + "RemediationProcedure": "Perform the following to enable server access logging: **From Console:** 1. Sign in to the AWS Management Console and open the S3 console at [https://console.aws.amazon.com/s3](https://console.aws.amazon.com/s3). 2. Under `All Buckets` click on the target S3 bucket. 3. Click on `Properties` in the top right of the console. 4. Under `Bucket: `, click `Logging`. 5. Configure bucket logging: - Check the `Enabled` box. - Select a Target Bucket from the list. - Enter a Target Prefix. 6. Click `Save`. **From Command Line:** 1. Get the name of the S3 bucket that CloudTrail is logging to: ``` aws cloudtrail describe-trails --region --query trailList[*].S3BucketName ``` 2. Copy and add the target bucket name at ``, the prefix for the log file at ``, and optionally add an email address in the following template, then save it as `.json`: ``` { LoggingEnabled: { TargetBucket: , TargetPrefix: , TargetGrants: [ { Grantee: { Type: AmazonCustomerByEmail, EmailAddress: }, Permission: FULL_CONTROL } ] } } ``` 3. Run the `put-bucket-logging` command with bucket name and `.json` as input; for more information, refer to [put-bucket-logging](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-logging.html): ``` aws s3api put-bucket-logging --bucket --bucket-logging-status file://.json ```", + "AuditProcedure": "Perform the following ensure that the CloudTrail S3 bucket has access logging is enabled: **From Console:** 1. Go to the Amazon CloudTrail console at [https://console.aws.amazon.com/cloudtrail/home](https://console.aws.amazon.com/cloudtrail/home). 2. In the API activity history pane on the left, click `Trails`. 3. In the Trails pane, note the bucket names in the S3 bucket column. 4. Sign in to the AWS Management Console and open the S3 console at [https://console.aws.amazon.com/s3](https://console.aws.amazon.com/s3). 5. Under `All Buckets` click on a target S3 bucket. 6. Click on `Properties` in the top right of the console. 7. Under `Bucket: `, click `Logging`. 8. Ensure `Enabled` is checked. **From Command Line:** 1. Get the name of the S3 bucket that CloudTrail is logging to: ``` aws cloudtrail describe-trails --query 'trailList[*].S3BucketName' ``` 2. Ensure logging is enabled on the bucket: ``` aws s3api get-bucket-logging --bucket ``` Ensure the command does not return an empty output. Sample output for a bucket with logging enabled: ``` { LoggingEnabled: { TargetPrefix: , TargetBucket: } } ```", + "AdditionalInformation": "", + "References": "https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html:https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html", + "DefaultValue": "Logging is disabled." + } + ] + }, + { + "Id": "3.5", + "Description": "Ensure CloudTrail logs are encrypted at rest using KMS CMKs", + "Checks": [ + "cloudtrail_kms_encryption_enabled" + ], + "Attributes": [ + { + "Section": "3 Logging", + "Profile": "Level 2", + "AssessmentStatus": "Automated", + "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer-created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.", + "RationaleStatement": "Configuring CloudTrail to use SSE-KMS provides additional confidentiality controls on log data, as a given user must have S3 read permission on the corresponding log bucket and must be granted decrypt permission by the CMK policy.", + "ImpactStatement": "Customer-created keys incur an additional cost. See https://aws.amazon.com/kms/pricing/ for more information.", + "RemediationProcedure": "Perform the following to configure CloudTrail to use SSE-KMS: **From Console:** 1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail). 2. In the left navigation pane, choose `Trails`. 3. Click on a trail. 4. Under the `S3` section, click the edit button (pencil icon). 5. Click `Advanced`. 6. Select an existing CMK from the `KMS key Id` drop-down menu. - **Note:** Ensure the CMK is located in the same region as the S3 bucket. - **Note:** You will need to apply a KMS key policy on the selected CMK in order for CloudTrail, as a service, to encrypt and decrypt log files using the CMK provided. View the AWS documentation for [editing the selected CMK Key policy](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-kms-key-policy-for-cloudtrail.html). 7. Click `Save`. 8. You will see a notification message stating that you need to have decryption permissions on the specified KMS key to decrypt log files. 9. Click `Yes`. **From Command Line:** Run the following command to specify a KMS key ID to use with a trail: ``` aws cloudtrail update-trail --name --kms-id ``` Run the following command to attach a key policy to a specified KMS key: ``` aws kms put-key-policy --key-id --policy ```", + "AuditProcedure": "Perform the following to determine if CloudTrail is configured to use SSE-KMS: **From Console:** 1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail). 2. In the left navigation pane, choose `Trails`. 3. Select a trail. 4. In the `General details` section, select `Edit` to edit the trail configuration. 5. Ensure the box at `Log file SSE-KMS encryption` is checked and that a valid `AWS KMS alias` of a KMS key is entered in the respective text box. **From Command Line:** 1. Run the following command: ``` aws cloudtrail describe-trails ``` 2. For each trail listed, SSE-KMS is enabled if the trail has a `KmsKeyId` property defined.", + "AdditionalInformation": "Three statements that need to be added to the CMK policy: 1\\. Enable CloudTrail to describe CMK properties: ```
    {  Sid: Allow CloudTrail access,  Effect: Allow,  Principal: {  Service: cloudtrail.amazonaws.com  },  Action: kms:DescribeKey,  Resource: * } ``` 2\\. Granting encrypt permissions: ``` 
    {  Sid: Allow CloudTrail to encrypt logs,  Effect: Allow,  Principal: {  Service: cloudtrail.amazonaws.com  },  Action: kms:GenerateDataKey*,  Resource: *,  Condition: {  StringLike: {  kms:EncryptionContext:aws:cloudtrail:arn: [  arn:aws:cloudtrail:*:aws-account-id:trail/*  ]  }  } } ``` 3\\. Granting decrypt permissions: ``` 
    {  Sid: Enable CloudTrail log decrypt permissions,  Effect: Allow,  Principal: {  AWS: arn:aws:iam::aws-account-id:user/username  },  Action: kms:Decrypt,  Resource: *,  Condition: {  Null: {  kms:EncryptionContext:aws:cloudtrail:arn: false  }  } } ```",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html:https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/update-trail.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/kms/put-key-policy.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "3.6",
    +      "Description": "Ensure rotation for customer-created symmetric CMKs is enabled",
    +      "Checks": [
    +        "kms_cmk_rotation_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "3 Logging",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key, which is key material stored within the KMS that is tied to the key ID of the customer-created customer master key (CMK). The backing key is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can occur transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation cannot be enabled for any asymmetric CMK.",
    +          "RationaleStatement": "Rotating encryption keys helps reduce the potential impact of a compromised key, as data encrypted with a new key cannot be accessed with a previous key that may have been exposed. Keys should be rotated every year or upon an event that could result in the compromise of that key.",
    +          "ImpactStatement": "Creation, management, and storage of CMKs may require additional time from an administrator.",
    +          "RemediationProcedure": "**From Console:** 1. Sign in to the AWS Management Console and open the KMS console at: [https://console.aws.amazon.com/kms](https://console.aws.amazon.com/kms). 2. In the left navigation pane, click `Customer-managed keys`. 3. Select a key with `Key spec = SYMMETRIC_DEFAULT` that does not have automatic rotation enabled. 4. Select the `Key rotation` tab. 5. Check the `Automatically rotate this KMS key every year` box. 6. Click `Save`. 7. Repeat steps 3–6 for all customer-managed CMKs that do not have automatic rotation enabled. **From Command Line:** 1. Run the following command to enable key rotation: ```  aws kms enable-key-rotation --key-id  ```",
    +          "AuditProcedure": "**From Console:** 1. Sign in to the AWS Management Console and open the KMS console at: [https://console.aws.amazon.com/kms](https://console.aws.amazon.com/kms). 2. In the left navigation pane, click `Customer-managed keys`. 3. Select a customer-managed CMK where `Key spec = SYMMETRIC_DEFAULT`. 4. Select the `Key rotation` tab. 5. Ensure the `Automatically rotate this KMS key every year` box is checked. 6. Repeat steps 3–5 for all customer-managed CMKs where `Key spec = SYMMETRIC_DEFAULT`. **From Command Line:** 1. Run the following command to get a list of all keys and their associated `KeyIds`: ```  aws kms list-keys ``` 2. For each key, note the KeyId and run the following command: ``` describe-key --key-id  ``` 3. If the response contains `KeySpec = SYMMETRIC_DEFAULT`, run the following command: ```  aws kms get-key-rotation-status --key-id  ``` 4. Ensure `KeyRotationEnabled` is set to `true`. 5. Repeat steps 2–4 for all remaining CMKs.",
    +          "AdditionalInformation": "",
    +          "References": "https://aws.amazon.com/kms/pricing/:https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "3.7",
    +      "Description": "Ensure VPC flow logging is enabled in all VPCs",
    +      "Checks": [
    +        "vpc_flow_logs_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "3 Logging",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet Rejects for VPCs.",
    +          "RationaleStatement": "VPC Flow Logs provide visibility into network traffic that traverses the VPC and can be used to detect anomalous traffic or gain insights during security workflows.",
    +          "ImpactStatement": "By default, CloudWatch Logs will store logs indefinitely unless a specific retention period is defined for the log group. When choosing the number of days to retain, keep in mind that the average time it takes for an organization to realize they have been breached is 210 days (at the time of this writing). Since additional time is required to research a breach, a minimum retention policy of 365 days allows for detection and investigation. You may also wish to archive the logs to a cheaper storage service rather than simply deleting them. See the following AWS resource to manage CloudWatch Logs retention periods: 1. https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/SettingLogRetention.html",
    +          "RemediationProcedure": "Perform the following to enable VPC Flow Logs: **From Console:** 1. Sign into the management console. 2. Select `Services`, then select `VPC`. 3. In the left navigation pane, select `Your VPCs`. 4. Select a VPC. 5. In the right pane, select the `Flow Logs` tab. 6. If no Flow Log exists, click `Create Flow Log`. 7. For Filter, select `Reject`. 8. Enter a `Role` and `Destination Log Group`. 9. Click `Create Log Flow`. 10. Click on `CloudWatch Logs Group`. **Note:** Setting the filter to Reject will dramatically reduce the accumulation of logging data for this recommendation and provide sufficient information for the purposes of breach detection, research, and remediation. However, during periods of least privilege security group engineering, setting the filter to All can be very helpful in discovering existing traffic flows required for the proper operation of an already running environment. **From Command Line:** 1. Create a policy document, name it `role_policy_document.json`, and paste the following content: ``` {  Version: 2012-10-17,  Statement: [  {  Sid: test,  Effect: Allow,  Principal: {  Service: ec2.amazonaws.com  },  Action: sts:AssumeRole  }  ] } ``` 2. Create another policy document, name it `iam_policy.json`, and paste the following content: ``` {  Version: 2012-10-17,  Statement: [  {  Effect: Allow,  Action:[  logs:CreateLogGroup,  logs:CreateLogStream,  logs:DescribeLogGroups,  logs:DescribeLogStreams,  logs:PutLogEvents,  logs:GetLogEvents,  logs:FilterLogEvents  ],  Resource: *  }  ] } ``` 3. Run the following command to create an IAM role: ``` aws iam create-role --role-name  --assume-role-policy-document file://role_policy_document.json  ``` 4. Run the following command to create an IAM policy: ``` aws iam create-policy --policy-name  --policy-document file://iam-policy.json ``` 5. Run the `attach-group-policy` command, using the IAM policy ARN returned from the previous step to attach the policy to the IAM role: ``` aws iam attach-group-policy --policy-arn arn:aws:iam:::policy/ --group-name  ``` - If the command succeeds, no output is returned. 6. Run the `describe-vpcs` command to get a list of VPCs in the selected region: ``` aws ec2 describe-vpcs --region  ``` - The command output should return a list of VPCs in the selected region. 7. Run the `create-flow-logs` command to create a flow log for a VPC: ``` aws ec2 create-flow-logs --resource-type VPC --resource-ids  --traffic-type REJECT --log-group-name  --deliver-logs-permission-arn  ``` 8. Repeat step 7 for other VPCs in the selected region. 9. Change the region by updating --region, and repeat the remediation procedure for each region.",
    +          "AuditProcedure": "Perform the following to determine if VPC Flow logs are enabled: **From Console:** 1. Sign into the management console. 2. Select `Services`, then select `VPC`. 3. In the left navigation pane, select `Your VPCs`. 4. Select a VPC. 5. In the right pane, select the `Flow Logs` tab. 6. Ensure a Log Flow exists that has `Active` in the `Status` column. **From Command Line:** 1. Run the `describe-vpcs` command (OSX/Linux/UNIX) to list the VPC networks available in the current AWS region: ``` aws ec2 describe-vpcs --region  --query Vpcs[].VpcId ``` 2. The command output returns the `VpcId` of VPCs available in the selected region. 3. Run the `describe-flow-logs` command (OSX/Linux/UNIX) using the VPC ID to determine if the selected virtual network has the Flow Logs feature enabled: ``` aws ec2 describe-flow-logs --filter Name=resource-id,Values= ``` - If there are no Flow Logs created for the selected VPC, the command output will return an empty list `[]`. 4. Repeat step 3 for other VPCs in the same region. 5. Change the region by updating `--region`, and repeat steps 1-4 for each region.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/flow-logs.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "3.8",
    +      "Description": "Ensure that object-level logging for write events is enabled for S3 buckets",
    +      "Checks": [
    +        "cloudtrail_s3_dataevents_write_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "3 Logging",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
    +          "RationaleStatement": "Enabling object-level logging will help you meet data compliance requirements within your organization, perform comprehensive security analyses, monitor specific patterns of user behavior in your AWS account, or take immediate actions on any object-level API activity within your S3 buckets using Amazon CloudWatch Events.",
    +          "ImpactStatement": "Enabling logging for these object-level events may significantly increase the number of events logged and may incur additional costs.",
    +          "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and navigate to the S3 dashboard at `https://console.aws.amazon.com/s3/`. 2. In the left navigation panel, click `buckets`, and then click the name of the S3 bucket you want to examine. 3. Click the `Properties` tab to see the bucket configuration in detail. 4. In the `AWS CloudTrail data events` section, select the trail name for recording activity. You can choose an existing trail or create a new one by clicking the `Configure in CloudTrail` button or navigating to the [CloudTrail console](https://console.aws.amazon.com/cloudtrail/). 5. Once the trail is selected, select the `Data Events` check box. 6. Select `S3` from the `Data event type` drop-down. 7. Select `Log all events` from the `Log selector template` drop-down. 8. Repeat steps 2-7 to enable object-level logging of write events for other S3 buckets. **From Command Line:** 1. To enable `object-level` data events logging for S3 buckets within your AWS account, run the `put-event-selectors` command using the name of the trail that you want to reconfigure as identifier: ``` aws cloudtrail put-event-selectors --region  --trail-name  --event-selectors '[{ ReadWriteType: WriteOnly, IncludeManagementEvents:true, DataResources: [{ Type: AWS::S3::Object, Values: [arn:aws:s3:::/] }] }]' ``` 2. The command output will be `object-level` event trail configuration. 3. If you want to enable it for all buckets at once, change the Values parameter to `[arn:aws:s3]` in the previous command. 4. Repeat step 1 for each s3 bucket to update `object-level` logging of write events. 5. Change the AWS region by updating the `--region` command parameter, and perform the process for the other regions.",
    +          "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and navigate to the CloudTrail dashboard at `https://console.aws.amazon.com/cloudtrail/`. 2. In the left panel, click `Trails`, and then click the name of the trail that you want to examine. 3. Review `General details`. 4. Confirm that `Multi-region trail` is set to `Yes`. 5. Scroll down to `Data events` and confirm the configuration: - If `advanced event selectors` is being used, it should read: ``` Data Events: S3 Log selector template Log all events ``` - If `basic event selectors` is being used, it should read: ``` Data events: S3 Bucket Name: All current and future S3 buckets Write: Enabled ``` 6. Repeat steps 2-5 to verify that each trail has multi-region enabled and is configured to log data events. If a trail does not have multi-region enabled and data event logging configured, refer to the remediation steps. **From Command Line:** 1. Run the `list-trails` command to list all trails: ``` aws cloudtrail list-trails ``` 2. The command output will be a list of trails: ``` TrailARN: arn:aws:cloudtrail:::trail/, Name: , HomeRegion:  ``` 3. Run the `get-trail` command to determine whether a trail is a multi-region trail: ``` aws cloudtrail get-trail --name  --region  ``` 4. The command output should include: `IsMultiRegionTrail: true`. 5. Run the `get-event-selectors` command, using the `Name` of the trail and the `region` returned in step 2, to determine if data event logging is configured: ``` aws cloudtrail get-event-selectors --region  --trail-name  --query EventSelectors[*].DataResources[] ``` 6. The command output should be an array that includes the S3 bucket defined for data event logging: ``` Type: AWS::S3::Object,  Values: [  arn:aws:s3 ``` 7. If the `get-event-selectors` command returns an empty array, data events are not included in the trail's logging configuration; therefore, object-level API operations performed on S3 buckets within your AWS account are not being recorded. 8. Repeat steps 1-7 to verify that each trail has multi-region enabled and is configured to log data events. If a trail does not have multi-region enabled and data event logging configured, refer to the remediation steps.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AmazonS3/latest/user-guide/enable-cloudtrail-events.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "3.9",
    +      "Description": "Ensure that object-level logging for read events is enabled for S3 buckets",
    +      "Checks": [
    +        "cloudtrail_s3_dataevents_read_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "3 Logging",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
    +          "RationaleStatement": "Enabling object-level logging will help you meet data compliance requirements within your organization, perform comprehensive security analyses, monitor specific patterns of user behavior in your AWS account, or take immediate actions on any object-level API activity within your S3 buckets using Amazon CloudWatch Events.",
    +          "ImpactStatement": "Enabling logging for these object-level events may significantly increase the number of events logged and may incur additional costs.",
    +          "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and navigate to S3 dashboard at `https://console.aws.amazon.com/s3/`. 2. In the left navigation panel, click `buckets` and then click the name of the S3 bucket that you want to examine. 3. Click the `Properties` tab to see the bucket configuration in detail. 4. In the `AWS Cloud Trail data events` section, select the trail name for recording activity. You can choose an existing trail or create a new one by clicking the `Configure in CloudTrail` button or navigating to the [CloudTrail console](https://console.aws.amazon.com/cloudtrail/). 5. Once the trail is selected, select the `Data Events` check box. 6. Select `S3` from the `Data event type` drop-down. 7. Select `Log all events` from the `Log selector template` drop-down. 8. Repeat steps 2-7 to enable object-level logging of read events for other S3 buckets. **From Command Line:** 1. To enable `object-level` data events logging for S3 buckets within your AWS account, run the `put-event-selectors` command using the name of the trail that you want to reconfigure as identifier: ``` aws cloudtrail put-event-selectors --region  --trail-name  --event-selectors '[{ ReadWriteType: ReadOnly, IncludeManagementEvents:true, DataResources: [{ Type: AWS::S3::Object, Values: [arn:aws:s3:::/] }] }]' ``` 2. The command output will be `object-level` event trail configuration. 3. If you want to enable it for all buckets at once, change the Values parameter to `[arn:aws:s3]` in the previous command. 4. Repeat step 1 for each s3 bucket to update `object-level` logging of read events. 5. Change the AWS region by updating the `--region` command parameter, and perform the process for the other regions.",
    +          "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and navigate to the CloudTrail dashboard at `https://console.aws.amazon.com/cloudtrail/`. 2. In the left panel, click `Trails`, and then click the name of the trail that you want to examine. 3. Review `General details`. 4. Confirm that `Multi-region trail` is set to `Yes` 5. Scroll down to `Data events` 5. Scroll down to `Data events` and confirm the configuration: - If `advanced event selectors` is being used, it should read: ``` Data Events: S3 Log selector template Log all events ``` - If `basic event selectors` is being used, it should read: ``` Data events: S3 Bucket Name: All current and future S3 buckets Read: Enabled ``` 6. Repeat steps 2-5 to verify that each trail has multi-region enabled and is configured to log data events. If a trail does not have multi-region enabled and data event logging configured, refer to the remediation steps. **From Command Line:** 1. Run the `describe-trails` command to list all trail names: ``` aws cloudtrail describe-trails --region  --output table --query trailList[*].Name ``` 2. The command output will be table of the trail names. 3. Run the `get-event-selectors` command using the name of a trail returned at the previous step and custom query filters to determine if data event logging is configured: ``` aws cloudtrail get-event-selectors --region  --trail-name  --query EventSelectors[*].DataResources[] ``` 4. The command output should be an array that includes the S3 bucket defined for data event logging. 5. If the `get-event-selectors` command returns an empty array, data events are not included in the trail's logging configuration; therefore, object-level API operations performed on S3 buckets within your AWS account are not being recorded. 6. Repeat steps 1-5 to verify the configuration of each trail. 7. Change the AWS region by updating the `--region` command parameter, and perform the audit process for other regions.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AmazonS3/latest/user-guide/enable-cloudtrail-events.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.1",
    +      "Description": "Ensure unauthorized API calls are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_unauthorized_api_calls"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring unauthorized API calls will help reduce the time it takes to detect malicious activity and can alert you to potential security incidents.",
    +          "ImpactStatement": "This alert may be triggered by normal read-only console activities that attempt to opportunistically gather optional information but gracefully fail if they lack the necessary permissions. If an excessive number of alerts are generated, then an organization may wish to consider adding read access to the limited IAM user permissions solely to reduce the number of alerts. In some cases, doing this may allow users to actually view some areas of the system; any additional access granted should be reviewed for alignment with the original limited IAM user intent.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for unauthorized API calls and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=unauthorized_api_calls_metric,metricNamespace=CISBenchmark,metricValue=1 --filter-pattern { ($.errorCode =*UnauthorizedOperation) || ($.errorCode =AccessDenied*) && ($.sourceIPAddress!=delivery.logs.amazonaws.com) && ($.eventName!=HeadBucket) }  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name unauthorized_api_calls_alarm --metric-name unauthorized_api_calls_metric --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace CISBenchmark --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.errorCode =*UnauthorizedOperation) || ($.errorCode =AccessDenied*) && ($.sourceIPAddress!=delivery.logs.amazonaws.com) && ($.eventName!=HeadBucket) },  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query MetricAlarms[?MetricName == ]  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://aws.amazon.com/sns/:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.2",
    +      "Description": "Ensure management console sign-in without MFA is monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_sign_in_without_mfa"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring for single-factor console logins will increase visibility into accounts that are not protected by MFA. These type of accounts are more susceptible to compromise and unauthorized access.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for AWS Management Console sign-ins without MFA and uses the `` taken from audit step 1.  ```  aws logs put-metric-filter --log-group-name  --filter-name `` --metric-transformations metricName= ``,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.additionalEventData.MFAUsed != Yes) }'  ```  Or, to reduce false positives in case Single Sign-On (SSO) is used in the organization:  ```  aws logs put-metric-filter --log-group-name  --filter-name `` --metric-transformations metricName= ``,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.additionalEventData.MFAUsed != Yes) && ($.userIdentity.type = IAMUser) && ($.responseElements.ConsoleLogin = Success) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails:  ```  aws cloudtrail describe-trails  ``` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  ```  aws cloudtrail get-trail-status --name   ```  - ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  ```  aws cloudtrail get-event-selectors --trail-name   ```  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = ConsoleLogin) && ($.additionalEventData.MFAUsed != Yes) }  ```  Or, to reduce false positives in case Single Sign-On (SSO) is used in the organization:  ```  filterPattern: { ($.eventName = ConsoleLogin) && ($.additionalEventData.MFAUsed != Yes) && ($.userIdentity.type = IAMUser) && ($.responseElements.ConsoleLogin = Success) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4.  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored Filter pattern set to `{ ($.eventName = ConsoleLogin) && ($.additionalEventData.MFAUsed != Yes) && ($.userIdentity.type = IAMUser) && ($.responseElements.ConsoleLogin = Success}`: - reduces false alarms raised when a user logs in via SSO",
    +          "References": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/viewing_metrics_with_cloudwatch.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.3",
    +      "Description": "Ensure usage of the 'root' account is monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_root_usage"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for 'root' login attempts to detect unauthorized use or attempts to use the root account.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring 'root' account logins will provide visibility into the use of a fully privileged account and the opportunity to reduce its usage.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for 'root' account usage and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name `` --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ $.userIdentity.type = Root && $.userIdentity.invokedBy NOT EXISTS && $.eventType != AwsServiceEvent }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails:  ```  aws cloudtrail describe-trails  ``` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  ```  aws cloudtrail get-trail-status --name   ```  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  ```  aws cloudtrail get-event-selectors --trail-name   ```  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { $.userIdentity.type = Root && $.userIdentity.invokedBy NOT EXISTS && $.eventType != AwsServiceEvent }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.4",
    +      "Description": "Ensure IAM policy changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_policy_changes"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to IAM policies will help ensure authentication and authorization controls remain intact.",
    +          "ImpactStatement": "Monitoring these changes may result in a number of false positives, especially in larger environments. This alert may require more tuning than others to eliminate some of those erroneous notifications.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for IAM policy changes and the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name `` --filter-name `` --metric-transformations metricName= ``,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrails:  ```  aws cloudtrail describe-trails  ``` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  ```  aws cloudtrail get-trail-status --name   ```  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  ```  aws cloudtrail get-event-selectors --trail-name   ```  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: {($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.5",
    +      "Description": "Ensure CloudTrail configuration changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be used to detect changes to CloudTrail's configurations.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to CloudTrail's configuration will help ensure sustained visibility into the activities performed in the AWS account.",
    +          "ImpactStatement": "Ensuring that changes to CloudTrail configurations are monitored enhances security by maintaining the integrity of logging mechanisms. Automated monitoring can provide real-time alerts; however, it may require additional setup and resources to configure and manage these alerts effectively. These steps can be performed manually within a company's existing SIEM platform in cases where CloudTrail logs are monitored outside of the AWS monitoring tools in CloudWatch.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for CloudTrail configuration changes and the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.6",
    +      "Description": "Ensure AWS Management Console authentication failures are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_authentication_failures"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring failed console logins may decrease the lead time to detect an attempt to brute-force a credential, which may provide an indicator, such as the source IP address, that can be used in other event correlations.",
    +          "ImpactStatement": "Monitoring for these failures may generate a large number of alerts, especially in larger environments.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for AWS management Console login failures and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = Failed authentication) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = ConsoleLogin) && ($.errorMessage = Failed authentication) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.7",
    +      "Description": "Ensure disabling or scheduled deletion of customer created CMKs is monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for customer-created CMKs that have changed state to disabled or are scheduled for deletion.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Data encrypted with disabled or deleted keys will no longer be accessible. Changes in the state of a CMK should be monitored to ensure that the change is intentional.",
    +          "ImpactStatement": "Creation, storage, and management of CMK may require additional labor compared to the use of AWS-managed keys.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for CMKs that have been disabled or scheduled for deletion and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{($.eventSource = kms.amazonaws.com) && (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion)) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: {($.eventSource = kms.amazonaws.com) && (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion)) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.8",
    +      "Description": "Ensure S3 bucket policy changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to S3 bucket policies may reduce the time it takes to detect and correct permissive policies on sensitive S3 buckets.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for changes to S3 bucket policies and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.9",
    +      "Description": "Ensure AWS Config configuration changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to the AWS Config configuration will help ensure sustained visibility of the configuration items within the AWS account.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for AWS Configuration changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventSource = config.amazonaws.com) && (($.eventName=StopConfigurationRecorder)||($.eventName=DeleteDeliveryChannel)||($.eventName=PutDeliveryChannel)||($.eventName=PutConfigurationRecorder)) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventSource = config.amazonaws.com) && (($.eventName=StopConfigurationRecorder)||($.eventName=DeleteDeliveryChannel)||($.eventName=PutDeliveryChannel)||($.eventName=PutConfigurationRecorder)) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.10",
    +      "Description": "Ensure security group changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_security_group_changes"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  Security groups are stateful packet filters that control ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established to detect changes to security groups.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to security groups will help ensure that resources and services are not unintentionally exposed.",
    +          "ImpactStatement": "This may require additional 'tuning' to eliminate false positives and filter out expected activity so that anomalies are easier to detect.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for security groups changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace=CISBenchmark,metricValue=1 --filter-pattern { ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) || ($.eventName = ModifySecurityGroupRules) }  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace CISBenchmark --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) || ($.eventName = ModifySecurityGroupRules) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query MetricAlarms[?MetricName==]  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored AWS has recently introduced a new API, ModifySecurityGroupRules, which modifies the rules of a security group.",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html:https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifySecurityGroupRules.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.11",
    +      "Description": "Ensure Network Access Control List (NACL) changes are monitored",
    +      "Checks": [
    +        "cloudwatch_changes_to_network_acls_alarm_configured"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for any changes made to NACLs.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to NACLs will help ensure that AWS resources and services are not unintentionally exposed.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for NACL changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.12",
    +      "Description": "Ensure changes to network gateways are monitored",
    +      "Checks": [
    +        "cloudwatch_changes_to_network_gateways_alarm_configured"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  Network gateways are required to send and receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to network gateways will help ensure that all ingress/egress traffic traverses the VPC border via a controlled path.",
    +          "ImpactStatement": "Monitoring changes to network gateways helps detect unauthorized modifications that could compromise network security. Implementing automated monitoring and alerts can improve incident response times, but it may require additional configuration and maintenance efforts.",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for network gateways changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ``` 5. Implement logging and alerting mechanisms:  ```  aws sns create-topic --name NetworkGatewayChangesAlerts  ````  ```  aws sns subscribe --topic-arn  --protocol email --notification-endpoint   ```  ```  aws cloudwatch put-metric-alarm --alarm-name NetworkGatewayChangesAlarm --metric-name GatewayChanges --namespace AWS/EC2 --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::` 8. Ensure automated monitoring is enabled:  ```  aws cloudwatch put-metric-alarm --alarm-name NetworkGatewayChanges --metric-name GatewayChanges --namespace AWS/EC2 --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --alarm-actions   ```",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.13",
    +      "Description": "Ensure route table changes are monitored",
    +      "Checks": [
    +        "cloudwatch_changes_to_network_route_tables_alarm_configured"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring changes to route tables will help ensure that all VPC traffic flows through the expected path and prevent any accidental or intentional modifications that may lead to uncontrolled network traffic. An alarm should be triggered every time an AWS API call is performed to create, replace, delete, or disassociate a route table.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for route table changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-pattern '{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: {($.eventSource = ec2.amazonaws.com) && ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.14",
    +      "Description": "Ensure VPC changes are monitored",
    +      "Checks": [
    +        "cloudwatch_changes_to_vpcs_alarm_configured"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is possible to have more than one VPC within an account; additionally, it is also possible to create a peer connection between two VPCs, enabling network traffic to route between them. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. VPCs in AWS are logically isolated virtual networks that can be used to launch AWS resources. Monitoring changes to VPC configurations will help ensure that VPC traffic flow is not negatively impacted. Changes to VPCs can affect network accessibility from the public internet and additionally impact VPC traffic flow to and from the resources launched in the VPC.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for VPC changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.15",
    +      "Description": "Ensure AWS Organizations changes are monitored",
    +      "Checks": [
    +        "cloudwatch_log_metric_filter_aws_organizations_changes"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.  It is recommended that a metric filter and alarm be established for changes made to AWS Organizations in the master AWS account.",
    +          "RationaleStatement": "CloudWatch is an AWS native service that allows you to observe and monitor resources and applications. CloudTrail logs can also be sent to an external Security Information and Event Management (SIEM) environment for monitoring and alerting. Monitoring AWS Organizations changes can help you prevent unwanted, accidental, or intentional modifications that may lead to unauthorized access or other security breaches. This monitoring technique helps ensure that any unexpected changes made within your AWS Organizations can be investigated and that any unwanted changes can be rolled back.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following steps to set up the metric filter, alarm, SNS topic, and subscription: 1. Create a metric filter based on the provided filter pattern that checks for AWS Organizations changes and uses the `` taken from audit step 1:  ```  aws logs put-metric-filter --log-group-name  --filter-name  --metric-transformations metricName=,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventSource = organizations.amazonaws.com) && (($.eventName = AcceptHandshake) || ($.eventName = AttachPolicy) || ($.eventName = CreateAccount) || ($.eventName = CreateOrganizationalUnit) || ($.eventName = CreatePolicy) || ($.eventName = DeclineHandshake) || ($.eventName = DeleteOrganization) || ($.eventName = DeleteOrganizationalUnit) || ($.eventName = DeletePolicy) || ($.eventName = DetachPolicy) || ($.eventName = DisablePolicyType) || ($.eventName = EnablePolicyType) || ($.eventName = InviteAccountToOrganization) || ($.eventName = LeaveOrganization) || ($.eventName = MoveAccount) || ($.eventName = RemoveAccountFromOrganization) || ($.eventName = UpdatePolicy) || ($.eventName = UpdateOrganizationalUnit)) }'  ```  **Note**: You can choose your own `metricName` and `metricNamespace` strings. Using the same `metricNamespace` for all Foundations Benchmark metrics will group them together. 2. Create an SNS topic that the alarm will notify:  ```  aws sns create-topic --name   ```  **Note**: You can execute this command once and then reuse the same topic for all monitoring alarms.  **Note**: Capture the `TopicArn` that is displayed when creating the SNS topic in step 2. 3. Create an SNS subscription for the topic created in step 2:  ```  aws sns subscribe --topic-arn  --protocol  --notification-endpoint   ```  **Note**: You can execute this command once and then reuse the same subscription for all monitoring alarms. 4. Create an alarm that is associated with the CloudWatch Logs metric filter created in step 1 and the SNS topic created in step 2:  ```  aws cloudwatch put-metric-alarm --alarm-name  --metric-name  --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions   ```",
    +          "AuditProcedure": "If you are using CloudTrail trails and CloudWatch, perform the following to ensure that there is at least one active multi-region CloudTrail trail with the prescribed metric filters and alarms configured: 1. Identify the log group name that is configured for use with the active multi-region CloudTrail trail: - List all CloudTrail trails: `aws cloudtrail describe-trails` - Identify multi-region CloudTrail trails: `Trails with IsMultiRegionTrail set to true` - Note the value associated with Name:`` - Note the `` within the value associated with CloudWatchLogsLogGroupArn  - Example: `arn:aws:logs:::log-group::*` - Ensure the identified multi-region CloudTrail trail is active:  - `aws cloudtrail get-trail-status --name `  - Ensure `IsLogging` is set to `TRUE` - Ensure the identified multi-region CloudTrail trail captures all management events:  - `aws cloudtrail get-event-selectors --trail-name `  - Ensure there is at least one `event selector` for a trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All` 2. Get a list of all associated metric filters for the `` captured in step 1:  ```  aws logs describe-metric-filters --log-group-name   ``` 3. Ensure the output from the above command contains the following:  ```  filterPattern: { ($.eventSource = organizations.amazonaws.com) && (($.eventName = AcceptHandshake) || ($.eventName = AttachPolicy) || ($.eventName = CreateAccount) || ($.eventName = CreateOrganizationalUnit) || ($.eventName = CreatePolicy) || ($.eventName = DeclineHandshake) || ($.eventName = DeleteOrganization) || ($.eventName = DeleteOrganizationalUnit) || ($.eventName = DeletePolicy) || ($.eventName = DetachPolicy) || ($.eventName = DisablePolicyType) || ($.eventName = EnablePolicyType) || ($.eventName = InviteAccountToOrganization) || ($.eventName = LeaveOrganization) || ($.eventName = MoveAccount) || ($.eventName = RemoveAccountFromOrganization) || ($.eventName = UpdatePolicy) || ($.eventName = UpdateOrganizationalUnit)) }  ``` 4. Note the `` value associated with the `filterPattern` from step 3. 5. Get a list of CloudWatch alarms, and filter on the `` captured in step 4:  ```  aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName==]'  ``` 6. Note the `AlarmActions` value; this will provide the SNS topic ARN value. 7. Ensure there is at least one active subscriber to the SNS topic:  ```  aws sns list-subscriptions-by-topic --topic-arn    ``` - At least one subscription should have SubscriptionArn with a valid AWS ARN.  - Example of valid SubscriptionArn: `arn:aws:sns::::`",
    +          "AdditionalInformation": "Configuring a log metric filter and alarm on a multi-region (global) CloudTrail trail: - ensures that activities from all regions (both used and unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored",
    +          "References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/organizations/latest/userguide/orgs_security_incident-response.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "4.16",
    +      "Description": "Ensure AWS Security Hub is enabled",
    +      "Checks": [
    +        "securityhub_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "4 Monitoring",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "Security Hub collects security data from various AWS accounts, services, and supported third-party partner products, helping you analyze your security trends and identify the highest-priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from the AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
    +          "RationaleStatement": "AWS Security Hub provides you with a comprehensive view of your security state in AWS and helps you check your environment against security industry standards and best practices, enabling you to quickly assess the security posture across your AWS accounts.",
    +          "ImpactStatement": "It is recommended that AWS Security Hub be enabled in all regions. AWS Security Hub requires that AWS Config be enabled.",
    +          "RemediationProcedure": "To grant the permissions required to enable Security Hub, attach the Security Hub managed policy `AWSSecurityHubFullAccess` to an IAM user, group, or role. Enabling Security Hub: **From Console:** 1. Use the credentials of the IAM identity to sign in to the Security Hub console. 2. When you open the Security Hub console for the first time, choose `Go to Security Hub`. 3. The `Security standards` section on the welcome page lists supported security standards. Check the box for a standard to enable it. 3. Choose `Enable Security Hub`. **From Command Line:** 1. Run the `enable-security-hub` command, including `--enable-default-standards` to enable the default standards: ``` aws securityhub enable-security-hub --enable-default-standards ``` 2. To enable Security Hub without the default standards, include `--no-enable-default-standards`: ``` aws securityhub enable-security-hub --no-enable-default-standards ```",
    +          "AuditProcedure": "Follow this process to evaluate AWS Security Hub configuration per region: **From Console:** 1. Sign in to the AWS Management Console and open the AWS Security Hub console at https://console.aws.amazon.com/securityhub/. 2. On the top right of the console, select the target Region. 3. If the Security Hub > Summary page is displayed, then Security Hub is set up for the selected region. 4. If presented with Setup Security Hub or Get Started With Security Hub, refer to the remediation steps. 5. Repeat steps 2 to 4 for each region. **From Command Line:** Run the following command to verify the Security Hub status: ``` aws securityhub describe-hub ``` This will list the Security Hub status by region. Check for a 'SubscribedAt' value. Example output: ``` {  HubArn: ,  SubscribedAt: 2022-08-19T17:06:42.398Z,  AutoEnableControls: true } ``` An error will be returned if Security Hub is not enabled. Example error: ``` An error occurred (InvalidAccessException) when calling the DescribeHub operation: Account  is not subscribed to AWS Security Hub ```",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-get-started.html:https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-enable.html#securityhub-enable-api:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/securityhub/enable-security-hub.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.2",
    +      "Description": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports",
    +      "Checks": [
    +        "ec2_networkacl_allow_ingress_any_port",
    +        "ec2_networkacl_allow_ingress_tcp_port_22",
    +        "ec2_networkacl_allow_ingress_tcp_port_3389"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
    +          "RationaleStatement": "Public access to remote server administration ports, such as 22 (when used for SSH, not SFTP) and 3389, increases the attack surface of resources and unnecessarily raises the risk of resource compromise.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "**From Console:** Perform the following steps to remediate a network ACL: 1. Login to the AWS VPC Console at https://console.aws.amazon.com/vpc/home. 2. In the left pane, click `Network ACLs`. 3. For each network ACL that needs remediation, perform the following:  - Select the network ACL.  - Click the `Inbound Rules` tab.  - Click `Edit inbound rules`.  - Either A) update the Source field to a range other than 0.0.0.0/0, or B) click `Delete` to remove the offending inbound rule.  - Click `Save`.",
    +          "AuditProcedure": "**From Console:** Perform the following steps to determine if the account is configured as prescribed: 1. Login to the AWS VPC Console at https://console.aws.amazon.com/vpc/home. 2. In the left pane, click `Network ACLs`. 3. For each network ACL, perform the following:  - Select the network ACL.  - Click the `Inbound Rules` tab.  - Ensure that no rule exists which has a port range that includes port `22` or `3389`, uses the protocols TCP (6), UDP (17), or ALL (-1), or other remote server administration ports for your environment, has a `Source` of `0.0.0.0/0`, and shows `ALLOW`. **Note:** A port value of `ALL` or a port range such as `0-3389` includes port `22`, `3389`, and potentially other remote server administration ports.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html:https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Security.html#VPC_Security_Comparison",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.3",
    +      "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports",
    +      "Checks": [
    +        "ec2_securitygroup_allow_ingress_from_internet_to_all_ports",
    +        "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
    +        "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
    +          "RationaleStatement": "Public access to remote server administration ports, such as 22 (when used for SSH, not SFTP) and 3389, increases the attack surface of resources and unnecessarily raises the risk of resource compromise.",
    +          "ImpactStatement": "When updating an existing environment, ensure that administrators have access to remote server administration ports through another mechanism before removing access by deleting the 0.0.0.0/0 inbound rule.",
    +          "RemediationProcedure": "Perform the following to implement the prescribed state: 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. In the left pane, click `Security Groups`. 3. For each security group, perform the following:  - Select the security group.  - Click the `Inbound Rules` tab.  - Click the `Edit inbound rules` button.  - Identify the rules to be edited or removed.  - Either A) update the Source field to a range other than 0.0.0.0/0, or B) click `Delete` to remove the offending inbound rule.  - Click `Save rules`.",
    +          "AuditProcedure": "Perform the following to determine if the account is configured as prescribed: 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. In the left pane, click `Security Groups`. 3. For each security group, perform the following:  - Select the security group.  - Click the `Inbound Rules` tab.  - Ensure that no rule exists which has a port range including port `22` or `3389`, uses the protocols TCP (6), UDP (17), or ALL (-1), or other remote server administration ports for your environment, and has a `Source` of `0.0.0.0/0`. **Note:** A port value of `ALL` or a port range such as `0-3389` includes port `22`, `3389`, and potentially other remote server administration ports.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html#deleting-security-group-rule",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.4",
    +      "Description": "Ensure no security groups allow ingress from ::/0 to remote server administration ports",
    +      "Checks": [
    +        "ec2_securitygroup_allow_ingress_from_internet_to_all_ports",
    +        "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
    +        "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`.",
    +          "RationaleStatement": "Public access to remote server administration ports, such as 22 (when used for SSH, not SFTP) and 3389, increases attack surface of resources and unnecessarily raises the risk of resource compromise.",
    +          "ImpactStatement": "When updating an existing environment, ensure that administrators have access to remote server administration ports through another mechanism before removing access by deleting the ::/0 inbound rule.",
    +          "RemediationProcedure": "Perform the following to implement the prescribed state: 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. In the left pane, click `Security Groups`. 3. For each security group, perform the following:  - Select the security group.  - Click the `Inbound Rules` tab.  - Click the `Edit inbound rules` button.  - Identify the rules to be edited or removed.  - Either A) update the Source field to a range other than ::/0, or B) Click `Delete` to remove the offending inbound rule.  - Click `Save rules`.",
    +          "AuditProcedure": "Perform the following to determine if the account is configured as prescribed: 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. In the left pane, click `Security Groups`. 3. For each security group, perform the following:  - Select the security group.  - Click the `Inbound Rules` tab.  - Ensure that no rule exists which has a port range including port `22`, `3389`, or other remote server administration ports for your environment, and has a `Source` of `::/0`. **Note:** A port value of `ALL` or a port range such as `0-3389` includes port `22`, `3389`, and potentially other remote server administration ports.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html#deleting-security-group-rule",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.5",
    +      "Description": "Ensure the default security group of every VPC restricts all traffic",
    +      "Checks": [
    +        "ec2_securitygroup_default_restrict_traffic"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Automated",
    +          "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If a security group is not specified when an instance is launched, it is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic, both inbound and outbound. The default VPC in every region should have its default security group updated to comply with the following:  - No inbound rules.  - No outbound rules. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. **Note:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly, as it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering by discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    +          "RationaleStatement": "Configuring all VPC default security groups to restrict all traffic will encourage the development of least privilege security groups and promote the mindful placement of AWS resources into security groups, which will, in turn, reduce the exposure of those resources.",
    +          "ImpactStatement": "Implementing this recommendation in an existing VPC that contains operating resources requires extremely careful migration planning, as the default security groups are likely enabling many ports that are unknown. Enabling VPC flow logging (for accepted connections) in an existing environment that is known to be breach-free will reveal the current pattern of ports being used for each instance to communicate successfully. The migration process should include: - Analyzing VPC flow logs to understand current traffic patterns. - Creating least privilege security groups based on the analyzed data. - Testing the new security group rules in a staging environment before applying them to production.",
    +          "RemediationProcedure": "Perform the following to implement the prescribed state: **Security Group Members** 1. Identify AWS resources that exist within the default security group. 2. Create a set of least-privilege security groups for those resources. 3. Place the resources in those security groups, removing the resources noted in step 1 from the default security group. **Security Group State** 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. Repeat the following steps for all VPCs, including the default VPC in each AWS region: 3. In the left pane, click `Security Groups`. 4. For each default security group, perform the following:  - Select the `default` security group.  - Click the `Inbound Rules` tab.  - Remove any inbound rules.  - Click the `Outbound Rules` tab.  - Remove any Outbound rules. **Recommended** IAM groups allow you to edit the name field. After remediating default group rules for all VPCs in all regions, edit this field to add text similar to DO NOT USE. DO NOT ADD RULES.",
    +          "AuditProcedure": "Perform the following to determine if the account is configured as prescribed: **Security Group State** 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. Repeat the following steps for all VPCs, including the default VPC in each AWS region: 3. In the left pane, click `Security Groups`. 4. For each default security group, perform the following:  - Select the `default` security group.  - Click the `Inbound Rules` tab and ensure no rules exist.  - Click the `Outbound Rules` tab and ensure no rules exist. **Security Group Members** 1. Login to the AWS VPC Console at [https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home). 2. Repeat the following steps for all default groups in all VPCs, including the default VPC in each AWS region: 3. In the left pane, click `Security Groups`. 4. Copy the ID of the default security group. 5. Change to the EC2 Management Console at https://console.aws.amazon.com/ec2/v2/home. 6. In the filter column type `Security Group ID : `.",
    +          "AdditionalInformation": "",
    +          "References": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html#default-security-group",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.6",
    +      "Description": "Ensure routing tables for VPC peering are least access",
    +      "Checks": [
    +        "vpc_peering_routing_tables_with_least_privilege"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 2",
    +          "AssessmentStatus": "Manual",
    +          "Description": "Once a VPC peering connection is established, routing tables must be updated to enable any connections between the peered VPCs. These routes can be as specific as desired, even allowing for the peering of a VPC to only a single host on the other side of the connection.",
    +          "RationaleStatement": "Being highly selective in peering routing tables is a very effective way to minimize the impact of a breach, as resources outside of these routes are inaccessible to the peered VPC.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "Remove and add route table entries to ensure that the least number of subnets or hosts required to accomplish the purpose of peering are routable. **From Command Line:** 1. For each `` that contains routes that are non-compliant with your routing policy (granting more access than desired), delete the non-compliant route: ``` aws ec2 delete-route --route-table-id  --destination-cidr-block  ``` 2. Create a new compliant route: ``` aws ec2 create-route --route-table-id  --destination-cidr-block  --vpc-peering-connection-id  ```",
    +          "AuditProcedure": "Review the routing tables of peered VPCs to determine whether they route all subnets of each VPC and whether this is necessary to accomplish the intended purposes of peering the VPCs. **From Command Line:** 1. List all the route tables from a VPC and check if the GatewayId is pointing to a `` (e.g., pcx-1a2b3c4d) and if the DestinationCidrBlock is as specific as desired: ``` aws ec2 describe-route-tables --filter Name=vpc-id,Values= --query RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId} ```",
    +          "AdditionalInformation": "If an organization has an AWS Transit Gateway implemented in its VPC architecture, it should look to apply the recommendation above for a least access routing architecture at the AWS Transit Gateway level, in combination with what must be implemented at the standard VPC route table. More specifically, to route traffic between two or more VPCs via a Transit Gateway, VPCs must have an attachment to a Transit Gateway route table as well as a route. Therefore, to avoid routing traffic between VPCs, an attachment to the Transit Gateway route table should only be added where there is an intention to route traffic between the VPCs. As Transit Gateways are capable of hosting multiple route tables, it is possible to group VPCs by attaching them to a common route table.",
    +          "References": "https://docs.aws.amazon.com/AmazonVPC/latest/PeeringGuide/peering-configurations-partial-access.html:https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc-peering-connection.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.7",
    +      "Description": "Ensure that the EC2 Metadata Service only allows IMDSv2",
    +      "Checks": [
    +        "ec2_instance_imdsv2_enabled"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
    +          "RationaleStatement": "Instance metadata is data about your instance that you can use to configure or manage the running instance. Instance metadata is divided into [categories](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html), such as host name, events, and security groups. When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method). With IMDSv2, every request is now protected by session authentication. A session begins and ends a series of requests that software running on an EC2 instance uses to access the locally stored EC2 instance metadata and credentials. Allowing Version 1 of the service may open EC2 instances to Server-Side Request Forgery (SSRF) attacks, so Amazon recommends utilizing Version 2 for better instance security.",
    +          "ImpactStatement": "",
    +          "RemediationProcedure": "From Console: 1. Sign in to the AWS Management Console and navigate to the EC2 dashboard at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/). 2. In the left navigation panel, under the `INSTANCES` section, choose `Instances`. 3. Select the EC2 instance that you want to examine. 4. Choose `Actions > Instance Settings > Modify instance metadata options`. 5. Set `Instance metadata service` to `Enable`. 6. Set `IMDSv2` to `Required`. 7. Repeat steps 1-6 to perform the remediation process for other EC2 instances in all applicable AWS region(s). From Command Line: 1. Run the `describe-instances` command, applying the appropriate filters to list the IDs of all existing EC2 instances currently available in the selected region:  ```   aws ec2 describe-instances --region  --output table --query Reservations[*].Instances[*].InstanceId  ``` 2. The command output should return a table with the requested instance IDs. 3. Run the `modify-instance-metadata-options` command with an instance ID obtained from the previous step to update the Instance Metadata Version:  ```  aws ec2 modify-instance-metadata-options --instance-id  --http-tokens required --region   ``` 4. Repeat steps 1-3 to perform the remediation process for other EC2 instances in the same AWS region. 5. Change the region by updating `--region` and repeat the process for other regions.",
    +          "AuditProcedure": "From Console: 1. Sign in to the AWS Management Console and navigate to the EC2 dashboard at https://console.aws.amazon.com/ec2/. 2. In the left navigation panel, under the `INSTANCES` section, choose `Instances`. 3. Select the EC2 instance that you want to examine. 4. Check the `IMDSv2` status, and ensure that it is set to `Required`. From Command Line: 1. Run the `describe-instances` command using appropriate filters to list the IDs of all existing EC2 instances currently available in the selected region:  ```  aws ec2 describe-instances --region  --output table --query Reservations[*].Instances[*].InstanceId  ``` 2. The command output should return a table with the requested instance IDs. 3. Run the `describe-instances` command using the instance ID returned in the previous step and apply custom filtering to determine whether the selected instance is using IMDSv2:  ```  aws ec2 describe-instances --region  --instance-ids  --query Reservations[*].Instances[*].MetadataOptions --output table  ``` 4. Ensure that for all EC2 instances, `HttpTokens` is set to `required` and `State` is set to `applied`. 5. Repeat steps 3 and 4 to verify the other EC2 instances provisioned within the current region. 6. Repeat steps 1–5 to perform the audit process for other AWS regions.",
    +          "AdditionalInformation": "",
    +          "References": "https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/:https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.1.1",
    +      "Description": "Ensure EBS volume encryption is enabled in all regions",
    +      "Checks": [
    +        "ec2_ebs_volume_encryption"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "SubSection": "5.1 Elastic Compute Cloud (EC2)",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
    +          "RationaleStatement": "Encrypting data at rest reduces the likelihood of unintentional exposure and can nullify the impact of disclosure if the encryption remains unbroken.",
    +          "ImpactStatement": "Losing access to or removing the KMS key used by the EBS volumes will result in the inability to access the volumes.",
    +          "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console and open the Amazon EC2 console using https://console.aws.amazon.com/ec2/. 2. Under `Account attributes`, click `EBS encryption`. 3. Click `Manage`. 4. Check the `Enable` box. 5. Click `Update EBS encryption`. 6. Repeat for each region in which EBS volume encryption is not enabled by default. **Note:** EBS volume encryption is configured per region. **From Command Line:** 1. Run the following command: ``` aws --region  ec2 enable-ebs-encryption-by-default ``` 2. Verify that `EbsEncryptionByDefault: true` is displayed. 3. Repeat for each region in which EBS volume encryption is not enabled by default. **Note:** EBS volume encryption is configured per region.",
    +          "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console and open the Amazon EC2 console using https://console.aws.amazon.com/ec2/. 2. Under `Settings`, click `EBS encryption`. 3. Verify `Always encrypt new EBS volumes` displays `Enabled`. 4. Repeat for each region in use. **Note:** EBS volume encryption is configured per region. **From Command Line:** 1. Run the following command: ``` aws --region  ec2 get-ebs-encryption-by-default ``` 2. Verify that `EbsEncryptionByDefault: true` is displayed. 3. Repeat for each region in use. **Note:** EBS volume encryption is configured per region.",
    +          "AdditionalInformation": "Default EBS volume encryption only applies to newly created EBS volumes; existing EBS volumes are **not** converted automatically.",
    +          "References": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html:https://aws.amazon.com/blogs/aws/new-opt-in-to-default-encryption-for-new-ebs-volumes/",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    },
    +    {
    +      "Id": "5.1.2",
    +      "Description": "Ensure CIFS access is restricted to trusted networks to prevent unauthorized access",
    +      "Checks": [
    +        "ec2_instance_port_cifs_exposed_to_internet"
    +      ],
    +      "Attributes": [
    +        {
    +          "Section": "5 Networking",
    +          "SubSection": "5.1 Elastic Compute Cloud (EC2)",
    +          "Profile": "Level 1",
    +          "AssessmentStatus": "Automated",
    +          "Description": "Common Internet File System (CIFS) is a network file-sharing protocol that allows systems to share files over a network. However, unrestricted CIFS access can expose your data to unauthorized users, leading to potential security risks. It is important to restrict CIFS access to only trusted networks and users to prevent unauthorized access and data breaches.",
    +          "RationaleStatement": "Allowing unrestricted CIFS access can lead to significant security vulnerabilities, as it may allow unauthorized users to access sensitive files and data. By restricting CIFS access to known and trusted networks, you can minimize the risk of unauthorized access and protect sensitive data from exposure to potential attackers. Implementing proper network access controls and permissions is essential for maintaining the security and integrity of your file-sharing systems.",
    +          "ImpactStatement": "Restricting CIFS access may require additional configuration and management effort. However, the benefits of enhanced security and reduced risk of unauthorized access to sensitive data far outweigh the potential challenges.",
    +          "RemediationProcedure": "**From Console:** 1. Login to the AWS Management Console. 2. Navigate to the EC2 Dashboard and select the Security Groups section under `Network & Security`. 3. Identify the security group that allows unrestricted ingress on port 445. 4. Select the security group and click the `Edit Inbound Rules` button. 5. Locate the rule allowing unrestricted access on port 445 (typically listed as `0.0.0.0/0` or `::/0`). 6. Modify the rule to restrict access to specific IP ranges or trusted networks only. 7. Save the changes to the security group. **From Command Line:** 1. Run the following command to remove or modify the unrestricted rule for CIFS access:  ```  aws ec2 revoke-security-group-ingress --region  --group-id  --protocol tcp --port 445 --cidr 0.0.0.0/0  ```  - Optionally, run the `authorise-security-group-ingress` command to create a new rule, specifying a trusted CIDR range instead of `0.0.0.0/0`. 2. Confirm the changes by describing the security group again and ensuring the unrestricted access rule has been removed or appropriately restricted:  ```  aws ec2 describe-security-groups --region  --group-ids  --query 'SecurityGroups[*].IpPermissions[?ToPort==`445`].{CIDR:IpRanges[*].CidrIp,Port:ToPort}'  ``` 3. Repeat the remediation for other security groups and regions as necessary.",
    +          "AuditProcedure": "**From Console:** 1. Login to the AWS Management Console. 2. Navigate to the EC2 Dashboard and select the Security Groups section under `Network & Security`. 3. Identify the security groups associated with instances or resources that may be using CIFS. 4. Review the inbound rules of each security group to check for rules that allow unrestricted access on port 445 (the port used by CIFS).  - Specifically, look for inbound rules that allow access from `0.0.0.0/0` or `::/0` on port 445. 5. Document any instances where unrestricted access is allowed and verify whether it is necessary for the specific use case. **From Command Line:** 1. Run the following command to list all security groups and identify those associated with CIFS:  ```  aws ec2 describe-security-groups --region  --query 'SecurityGroups[*].GroupId'  ``` 2. Check for any inbound rules that allow unrestricted access on port 445 using the following command:  ```  aws ec2 describe-security-groups --region  --group-ids  --query 'SecurityGroups[*].IpPermissions[?ToPort==`445`].{CIDR:IpRanges[*].CidrIp,Port:ToPort}'  ```  - Look for `0.0.0.0/0` or `::/0` in the output, which indicates unrestricted access. 3. Repeat the audit for other regions and security groups as necessary.",
    +          "AdditionalInformation": "",
    +          "References": "",
    +          "DefaultValue": ""
    +        }
    +      ]
    +    }
    +  ]
    +}
    
    From a2362b4bbcf6b356b57e18bef0e94d7c6aede716 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= 
    Date: Mon, 19 May 2025 09:42:04 +0200
    Subject: [PATCH 337/359] fix(cis): rename and add sections and subsections
     (#7738)
    
    ---
     prowler/CHANGELOG.md                          |   1 +
     prowler/compliance/aws/cis_1.4_aws.json       | 128 ++---
     prowler/compliance/aws/cis_1.5_aws.json       | 144 ++---
     prowler/compliance/aws/cis_2.0_aws.json       | 142 ++---
     prowler/compliance/aws/cis_3.0_aws.json       | 140 ++---
     prowler/compliance/aws/cis_4.0_aws.json       |  53 --
     prowler/compliance/azure/cis_2.0_azure.json   | 302 +++++------
     prowler/compliance/azure/cis_2.1_azure.json   | 298 +++++------
     prowler/compliance/azure/cis_3.0_azure.json   | 486 ++++++++---------
     prowler/compliance/gcp/cis_2.0_gcp.json       | 206 +++----
     prowler/compliance/gcp/cis_3.0_gcp.json       | 206 +++----
     .../kubernetes/cis_1.10_kubernetes.json       | 506 +++++++++---------
     .../kubernetes/cis_1.8_kubernetes.json        | 246 ++++-----
     prowler/compliance/m365/cis_4.0_m365.json     | 378 ++++++++-----
     .../lib/outputs/compliance/cis/cis_m365.py    |   2 +
     prowler/lib/outputs/compliance/cis/models.py  |   1 +
     .../outputs/compliance/cis/cis_m365_test.py   | 182 +++++++
     tests/lib/outputs/compliance/fixtures.py      |  52 ++
     18 files changed, 1892 insertions(+), 1581 deletions(-)
     create mode 100644 tests/lib/outputs/compliance/cis/cis_m365_test.py
    
    diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md
    index 55107c7b56..f0f2f8a57c 100644
    --- a/prowler/CHANGELOG.md
    +++ b/prowler/CHANGELOG.md
    @@ -24,6 +24,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
     
     ### Fixed
     - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699)
    +- Update and upgrade CIS for all the providers [(#7738)](https://github.com/prowler-cloud/prowler/pull/7738)
     - Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750)
     - Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764)
     
    diff --git a/prowler/compliance/aws/cis_1.4_aws.json b/prowler/compliance/aws/cis_1.4_aws.json
    index 584ca284c6..0e6d1f136c 100644
    --- a/prowler/compliance/aws/cis_1.4_aws.json
    +++ b/prowler/compliance/aws/cis_1.4_aws.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.  An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
    @@ -33,7 +33,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
    @@ -54,7 +54,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require.   Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user.   AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
    @@ -76,7 +76,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
    @@ -97,7 +97,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
    @@ -118,7 +118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
    @@ -139,7 +139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy.   Only the third implementation is recommended.",
    @@ -161,7 +161,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
    @@ -182,7 +182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
    @@ -203,7 +203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
    @@ -224,7 +224,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates.  Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
    @@ -245,7 +245,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
    @@ -266,7 +266,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable IAM Access analyzer for IAM policies about all resources in each region.  IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
    @@ -287,7 +287,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
    @@ -308,7 +308,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
    @@ -329,7 +329,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
    @@ -350,7 +350,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.  **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
    @@ -371,7 +371,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
    @@ -392,7 +392,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
    @@ -413,7 +413,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
    @@ -434,7 +434,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
    @@ -455,8 +455,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
    @@ -477,8 +477,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
    @@ -499,8 +499,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
    @@ -521,8 +521,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
    @@ -544,8 +544,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
    @@ -566,7 +566,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    +          "Section": "2 Storage",
               "SubSection": "2.2. Elastic Compute Cloud (EC2)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -589,8 +589,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
    @@ -611,7 +611,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
    @@ -632,7 +632,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -653,7 +653,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -674,7 +674,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
    @@ -695,7 +695,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
    @@ -716,7 +716,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs.  Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
    @@ -737,7 +737,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
    @@ -758,7 +758,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
    @@ -779,7 +779,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
    @@ -800,7 +800,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
    @@ -821,7 +821,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
    @@ -842,7 +842,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    @@ -863,7 +863,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
    @@ -884,7 +884,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
    @@ -905,7 +905,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    @@ -926,7 +926,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
    @@ -947,7 +947,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    @@ -968,7 +968,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
    @@ -989,7 +989,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    @@ -1010,7 +1010,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
    @@ -1031,7 +1031,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
    @@ -1052,7 +1052,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1073,7 +1073,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    @@ -1094,7 +1094,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
    @@ -1115,7 +1115,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    @@ -1136,7 +1136,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1159,7 +1159,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1182,7 +1182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1203,7 +1203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic.  The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.  **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    @@ -1224,7 +1224,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
    diff --git a/prowler/compliance/aws/cis_1.5_aws.json b/prowler/compliance/aws/cis_1.5_aws.json
    index 90ca3742e4..8c3d9a25a1 100644
    --- a/prowler/compliance/aws/cis_1.5_aws.json
    +++ b/prowler/compliance/aws/cis_1.5_aws.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.  An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
    @@ -33,7 +33,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
    @@ -54,7 +54,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require.   Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user.   AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
    @@ -76,7 +76,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
    @@ -97,7 +97,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
    @@ -118,7 +118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
    @@ -139,7 +139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy.   Only the third implementation is recommended.",
    @@ -161,7 +161,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
    @@ -182,7 +182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
    @@ -203,7 +203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
    @@ -224,7 +224,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates.  Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
    @@ -245,7 +245,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
    @@ -266,7 +266,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable IAM Access analyzer for IAM policies about all resources in each region.  IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
    @@ -287,7 +287,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
    @@ -308,7 +308,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
    @@ -329,7 +329,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
    @@ -350,7 +350,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.  **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
    @@ -371,7 +371,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
    @@ -392,7 +392,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
    @@ -413,7 +413,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
    @@ -434,7 +434,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
    @@ -455,8 +455,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
    @@ -477,8 +477,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
    @@ -499,8 +499,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
    @@ -521,8 +521,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
    @@ -544,8 +544,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
    @@ -566,8 +566,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.2. Elastic Compute Cloud (EC2)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.2 Elastic Compute Cloud (EC2)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
    @@ -589,8 +589,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
    @@ -611,8 +611,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
    @@ -633,8 +633,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
    @@ -655,7 +655,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    +          "Section": "2 Storage",
               "SubSection": "2.4 Elastic File System (EFS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -677,7 +677,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
    @@ -698,7 +698,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -719,7 +719,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -740,7 +740,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
    @@ -761,7 +761,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
    @@ -782,7 +782,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs.  Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
    @@ -803,7 +803,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
    @@ -824,7 +824,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
    @@ -845,7 +845,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
    @@ -866,7 +866,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
    @@ -887,7 +887,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
    @@ -908,7 +908,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    @@ -929,7 +929,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
    @@ -950,7 +950,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
    @@ -971,7 +971,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    @@ -992,7 +992,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
    @@ -1013,7 +1013,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    @@ -1034,7 +1034,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
    @@ -1055,7 +1055,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
    @@ -1076,7 +1076,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    @@ -1097,7 +1097,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
    @@ -1118,7 +1118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
    @@ -1139,7 +1139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1160,7 +1160,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    @@ -1181,7 +1181,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
    @@ -1202,7 +1202,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    @@ -1223,7 +1223,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1246,7 +1246,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1269,7 +1269,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1292,7 +1292,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1313,7 +1313,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic.  The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.  **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    @@ -1334,7 +1334,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
    diff --git a/prowler/compliance/aws/cis_2.0_aws.json b/prowler/compliance/aws/cis_2.0_aws.json
    index 1d12e296d5..b847e5e38e 100644
    --- a/prowler/compliance/aws/cis_2.0_aws.json
    +++ b/prowler/compliance/aws/cis_2.0_aws.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.  An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
    @@ -33,7 +33,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
    @@ -54,7 +54,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require.   Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user.   AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
    @@ -76,7 +76,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
    @@ -97,7 +97,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
    @@ -118,7 +118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
    @@ -139,7 +139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy.   Only the third implementation is recommended.",
    @@ -161,7 +161,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
    @@ -182,7 +182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
    @@ -203,7 +203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
    @@ -224,7 +224,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates.  Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
    @@ -245,7 +245,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
    @@ -266,7 +266,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable IAM Access analyzer for IAM policies about all resources in each region.  IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
    @@ -287,7 +287,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
    @@ -308,7 +308,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers.",
    @@ -329,7 +329,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
    @@ -350,7 +350,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
    @@ -371,7 +371,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.  **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
    @@ -392,7 +392,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
    @@ -413,7 +413,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
    @@ -434,7 +434,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
    @@ -455,7 +455,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
    @@ -476,7 +476,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    +          "Section": "2 Storage",
               "SubSection": "2.1. Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -499,8 +499,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
    @@ -521,8 +521,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
    @@ -544,8 +544,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
    @@ -566,8 +566,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.2. Elastic Compute Cloud (EC2)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.2 Elastic Compute Cloud (EC2)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
    @@ -589,8 +589,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
    @@ -611,8 +611,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
    @@ -633,8 +633,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
    @@ -655,7 +655,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    +          "Section": "2 Storage",
               "SubSection": "2.4 Elastic File System (EFS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -677,7 +677,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
    @@ -698,7 +698,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -719,7 +719,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -740,7 +740,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
    @@ -761,7 +761,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
    @@ -782,7 +782,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs.  Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
    @@ -803,7 +803,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
    @@ -824,7 +824,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
    @@ -845,7 +845,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
    @@ -866,7 +866,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
    @@ -887,7 +887,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
    @@ -908,7 +908,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    @@ -929,7 +929,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
    @@ -950,7 +950,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
    @@ -971,7 +971,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    @@ -992,7 +992,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
    @@ -1013,7 +1013,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    @@ -1034,7 +1034,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
    @@ -1055,7 +1055,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
    @@ -1076,7 +1076,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    @@ -1097,7 +1097,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
    @@ -1118,7 +1118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
    @@ -1139,7 +1139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1160,7 +1160,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    @@ -1181,7 +1181,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
    @@ -1202,7 +1202,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    @@ -1223,7 +1223,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1246,7 +1246,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1269,7 +1269,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1292,7 +1292,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1313,7 +1313,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic.  The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.  **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    @@ -1334,7 +1334,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
    @@ -1356,7 +1356,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
    diff --git a/prowler/compliance/aws/cis_3.0_aws.json b/prowler/compliance/aws/cis_3.0_aws.json
    index 9b45e6c7b8..9b9ff78ded 100644
    --- a/prowler/compliance/aws/cis_3.0_aws.json
    +++ b/prowler/compliance/aws/cis_3.0_aws.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.  An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
    @@ -33,7 +33,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
    @@ -54,7 +54,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require.   Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user.   AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
    @@ -76,7 +76,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
    @@ -97,7 +97,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
    @@ -118,7 +118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
    @@ -139,7 +139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy.   Only the third implementation is recommended.",
    @@ -161,7 +161,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
    @@ -182,7 +182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
    @@ -203,7 +203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
    @@ -224,7 +224,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates.  Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
    @@ -245,7 +245,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
    @@ -266,7 +266,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable IAM Access analyzer for IAM policies about all resources in each region.  IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
    @@ -287,7 +287,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
    @@ -306,7 +306,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers.",
    @@ -327,7 +327,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
    @@ -348,7 +348,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
    @@ -369,7 +369,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.  **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
    @@ -390,7 +390,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
    @@ -411,7 +411,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
    @@ -432,7 +432,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
    @@ -453,7 +453,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
    @@ -474,8 +474,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
    @@ -496,8 +496,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
    @@ -518,8 +518,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
    @@ -541,8 +541,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.1. Simple Storage Service (S3)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.1 Simple Storage Service (S3)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
    @@ -563,8 +563,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.2. Elastic Compute Cloud (EC2)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.2 Elastic Compute Cloud (EC2)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
    @@ -585,8 +585,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
    @@ -607,8 +607,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
    @@ -629,8 +629,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    -          "SubSection": "2.3. Relational Database Service (RDS)",
    +          "Section": "2 Storage",
    +          "SubSection": "2.3 Relational Database Service (RDS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to anypublicly accessible RDS database instance, you must disable the database PubliclyAccessible flag and update the VPC security group associated with the instance",
    @@ -651,7 +651,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Storage",
    +          "Section": "2 Storage",
               "SubSection": "2.4 Elastic File System (EFS)",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -673,7 +673,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
    @@ -694,7 +694,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -715,7 +715,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
    @@ -736,7 +736,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
    @@ -757,7 +757,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
    @@ -778,7 +778,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
    @@ -799,7 +799,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
    @@ -820,7 +820,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
    @@ -841,7 +841,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Logging",
    +          "Section": "3 Logging",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
    @@ -862,7 +862,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    @@ -883,7 +883,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
    @@ -904,7 +904,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
    @@ -925,7 +925,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    @@ -946,7 +946,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
    @@ -967,7 +967,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    @@ -988,7 +988,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
    @@ -1009,7 +1009,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
    @@ -1030,7 +1030,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    @@ -1051,7 +1051,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
    @@ -1072,7 +1072,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
    @@ -1093,7 +1093,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1114,7 +1114,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    @@ -1135,7 +1135,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
    @@ -1156,7 +1156,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    @@ -1177,7 +1177,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Monitoring",
    +          "Section": "4 Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
    @@ -1200,7 +1200,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1223,7 +1223,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1246,7 +1246,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
    @@ -1267,7 +1267,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic.  The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.  **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    @@ -1288,7 +1288,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
    @@ -1309,7 +1309,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Networking",
    +          "Section": "5 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
    diff --git a/prowler/compliance/aws/cis_4.0_aws.json b/prowler/compliance/aws/cis_4.0_aws.json
    index d026a21962..cd8edb322a 100644
    --- a/prowler/compliance/aws/cis_4.0_aws.json
    +++ b/prowler/compliance/aws/cis_4.0_aws.json
    @@ -13,7 +13,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of the Acceptable Use Policy or indicative of a likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
    @@ -36,7 +35,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
    @@ -59,7 +57,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
    @@ -82,7 +79,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted.",
    @@ -105,7 +101,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.**Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is kept charged and secured, independent of any individual personal devices (non-personal virtual MFA). This lessens the risks of losing access to the MFA due to device loss, device trade-in, or if the individual owning the device is no longer employed at the company.",
    @@ -128,7 +123,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
    @@ -151,7 +145,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
    @@ -174,7 +167,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are at least a given length. It is recommended that the password policy require a minimum password length 14.",
    @@ -197,7 +189,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
    @@ -220,7 +211,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
    @@ -243,7 +233,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
    @@ -267,7 +256,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused for 45 days or more be deactivated or removed.",
    @@ -290,7 +278,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
    @@ -313,7 +300,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be rotated regularly.",
    @@ -336,7 +322,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM users are granted access to services, functions, and data through IAM policies. There are four ways to define policies for a user: 1) Edit the user policy directly, also known as an inline or user policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy; 4) add the user to an IAM group that has an inline policy.Only the third implementation is recommended.",
    @@ -360,7 +345,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered standard security advice to grant least privilege—that is, granting only the permissions required to perform a task. Determine what users need to do, and then craft policies for them that allow the users to perform only those tasks, instead of granting full administrative privileges.",
    @@ -383,7 +367,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role, with the appropriate policy assigned, to allow authorized users to manage incidents with AWS Support.",
    @@ -406,7 +389,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. AWS Access means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
    @@ -429,7 +411,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use AWS Certificate Manager (ACM) or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
    @@ -452,7 +433,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable the IAM Access Analyzer for IAM policies regarding all resources in each active AWS region.IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. The results allow you to determine whether an unintended user is permitted, making it easier for administrators to monitor least privilege access. Access Analyzer analyzes only the policies that are applied to resources in the same AWS Region.",
    @@ -475,7 +455,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
    @@ -498,7 +477,6 @@
           "Attributes": [
             {
               "Section": "1 Identity and Access Management",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment, a user has sudo permissions and can access the internet. Therefore, it is feasible to install file transfer software, for example, and move data from CloudShell to external internet servers.",
    @@ -730,7 +708,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
    @@ -753,7 +730,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or remained unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled for all CloudTrails.",
    @@ -776,7 +752,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration items (AWS resources), relationships between configuration items (AWS resources), and any configuration changes between resources. It is recommended that AWS Config be enabled in all regions.",
    @@ -799,7 +774,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Server access logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that server access logging be enabled on the CloudTrail S3 bucket.",
    @@ -822,7 +796,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer-created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
    @@ -845,7 +818,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key, which is key material stored within the KMS that is tied to the key ID of the customer-created customer master key (CMK). The backing key is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can occur transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation cannot be enabled for any asymmetric CMK.",
    @@ -868,7 +840,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet Rejects for VPCs.",
    @@ -891,7 +862,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
    @@ -914,7 +884,6 @@
           "Attributes": [
             {
               "Section": "3 Logging",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
    @@ -937,7 +906,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
    @@ -960,7 +928,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
    @@ -983,7 +950,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts to detect unauthorized use or attempts to use the root account.",
    @@ -1006,7 +972,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies.",
    @@ -1029,7 +994,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be used to detect changes to CloudTrail's configurations.",
    @@ -1052,7 +1016,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
    @@ -1075,7 +1038,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer-created CMKs that have changed state to disabled or are scheduled for deletion.",
    @@ -1098,7 +1060,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
    @@ -1121,7 +1082,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations.",
    @@ -1144,7 +1104,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Security groups are stateful packet filters that control ingress and egress traffic within a VPC.It is recommended that a metric filter and alarm be established to detect changes to security groups.",
    @@ -1167,7 +1126,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for any changes made to NACLs.",
    @@ -1190,7 +1148,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send and receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
    @@ -1213,7 +1170,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways.It is recommended that a metric filter and alarm be established for changes to route tables.",
    @@ -1236,7 +1192,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than one VPC within an account; additionally, it is also possible to create a peer connection between two VPCs, enabling network traffic to route between them.It is recommended that a metric filter and alarm be established for changes made to VPCs.",
    @@ -1259,7 +1214,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to AWS Organizations in the master AWS account.",
    @@ -1282,7 +1236,6 @@
           "Attributes": [
             {
               "Section": "4 Monitoring",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Security Hub collects security data from various AWS accounts, services, and supported third-party partner products, helping you analyze your security trends and identify the highest-priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from the AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
    @@ -1307,7 +1260,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
    @@ -1332,7 +1284,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
    @@ -1357,7 +1308,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`.",
    @@ -1380,7 +1330,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If a security group is not specified when an instance is launched, it is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic, both inbound and outbound.The default VPC in every region should have its default security group updated to comply with the following: - No inbound rules. - No outbound rules.Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.**Note:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly, as it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering by discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
    @@ -1403,7 +1352,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Once a VPC peering connection is established, routing tables must be updated to enable any connections between the peered VPCs. These routes can be as specific as desired, even allowing for the peering of a VPC to only a single host on the other side of the connection.",
    @@ -1426,7 +1374,6 @@
           "Attributes": [
             {
               "Section": "5 Networking",
    -          "SubSection": "",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
    diff --git a/prowler/compliance/azure/cis_2.0_azure.json b/prowler/compliance/azure/cis_2.0_azure.json
    index 59ab14879d..94983dab94 100644
    --- a/prowler/compliance/azure/cis_2.0_azure.json
    +++ b/prowler/compliance/azure/cis_2.0_azure.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -35,7 +35,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -58,7 +58,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -79,7 +79,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -102,7 +102,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -123,7 +123,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -144,7 +144,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -165,7 +165,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -186,7 +186,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -207,7 +207,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -230,7 +230,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Require administrators or appropriately delegated users to create new tenants.",
    @@ -250,7 +250,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources a a guest user.",
    @@ -270,7 +270,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed.",
    @@ -290,7 +290,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensures that two alternate forms of identification are provided before allowing a password reset.",
    @@ -310,7 +310,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy.",
    @@ -330,7 +330,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0.",
    @@ -350,7 +350,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that users are notified on their primary and secondary emails on password resets.",
    @@ -370,7 +370,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that all Global Administrators are notified if any other administrator resets their password.",
    @@ -392,7 +392,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators to provide consent for applications before use.",
    @@ -414,7 +414,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Allow users to provide consent for selected permissions when a request is coming from a verified publisher.",
    @@ -434,7 +434,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators to provide consent for the apps before use.",
    @@ -456,7 +456,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators or appropriately delegated users to register third-party applications.",
    @@ -478,7 +478,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Limit guest user permissions.",
    @@ -500,7 +500,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict invitations to users with specific administrative roles only.",
    @@ -520,7 +520,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Restrict access to the Azure AD administration portal to administrators only. NOTE: This only affects access to the Azure AD administrator's web portal. This setting does not prohibit privileged users from using other methods such as Rest API or Powershell to obtain sensitive information from Azure AD.",
    @@ -540,7 +540,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restricts group creation to administrators with permissions only.",
    @@ -562,7 +562,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group creation to administrators only.",
    @@ -582,7 +582,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group management to administrators only.",
    @@ -604,7 +604,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict Microsoft 365 group creation to administrators only.",
    @@ -624,7 +624,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Joining or registering devices to the active directory should require Multi-factor authentication.",
    @@ -646,7 +646,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.",
    @@ -668,7 +668,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration.",
    @@ -688,7 +688,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories.",
    @@ -710,7 +710,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -733,7 +733,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -756,7 +756,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -779,7 +779,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -802,7 +802,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -825,7 +825,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -848,7 +848,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -871,7 +871,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -894,7 +894,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -917,7 +917,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -940,7 +940,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -963,7 +963,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -986,7 +986,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -1009,7 +1009,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -1032,7 +1032,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -1055,7 +1055,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1076,7 +1076,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1099,7 +1099,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1122,7 +1122,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1145,7 +1145,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1168,7 +1168,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1191,7 +1191,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1214,7 +1214,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.2 Microsoft Defender for IoT",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1237,7 +1237,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable data encryption in transit.",
    @@ -1259,7 +1259,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions.",
    @@ -1279,7 +1279,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure.",
    @@ -1301,7 +1301,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "For increased security, regenerate storage account access keys periodically.",
    @@ -1321,7 +1321,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.",
    @@ -1341,7 +1341,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Expire shared access signature tokens within an hour.",
    @@ -1363,7 +1363,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Disallowing public access for a storage account overrides the public access settings for individual containers in that storage account.",
    @@ -1385,7 +1385,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed.",
    @@ -1407,7 +1407,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Azure services exception is enabled, the following services are granted access to the storage account: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor, and Azure SQL Data Warehouse (when registered in the subscription).",
    @@ -1429,7 +1429,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it.",
    @@ -1451,7 +1451,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability. It is recommended that both Azure Containers with attached Blob Storage and standalone containers with Blob Storage be made recoverable by enabling the soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted.",
    @@ -1473,7 +1473,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys.",
    @@ -1493,7 +1493,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1513,7 +1513,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1535,7 +1535,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In some cases, Azure Storage sets the minimum TLS versio n to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLSversion can be configured to be later protocols such as TLS 1.2.",
    @@ -1557,7 +1557,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1580,7 +1580,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1603,7 +1603,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1626,7 +1626,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1649,7 +1649,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1672,7 +1672,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1695,7 +1695,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1718,7 +1718,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1741,7 +1741,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1764,7 +1764,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1787,7 +1787,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1810,7 +1810,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1833,7 +1833,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1856,7 +1856,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1879,7 +1879,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1902,7 +1902,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1925,7 +1925,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1948,7 +1948,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1969,7 +1969,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1992,7 +1992,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2015,7 +2015,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2038,7 +2038,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2061,7 +2061,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2084,7 +2084,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2107,7 +2107,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2130,7 +2130,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2153,7 +2153,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -2176,7 +2176,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2199,7 +2199,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2222,7 +2222,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2245,7 +2245,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2268,7 +2268,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2291,7 +2291,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2314,7 +2314,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2337,7 +2337,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2360,7 +2360,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2383,7 +2383,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2406,7 +2406,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2429,7 +2429,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2452,7 +2452,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2475,7 +2475,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2498,7 +2498,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2521,7 +2521,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2542,7 +2542,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. Currently, 95 Azure resources support Azure Monitoring (See the more information section for a complete list), including Network Security Groups, Load Balancers, Key Vault, AD, Logic Apps, and CosmosDB. The content of these logs varies by resource type. A number of back-end services were not configured to log and store Resource Logs for certain activities or for a sufficient length. It is crucial that monitoring is correctly configured to log all relevant activities and retain those logs for a sufficient length of time. Given that the mean time to detection in an enterprise is 240 days, a minimum retention period of two years is recommended.",
    @@ -2562,7 +2562,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads.",
    @@ -2584,7 +2584,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.3 Configuring Application Insights",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2607,7 +2607,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2629,7 +2629,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2651,7 +2651,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2673,7 +2673,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured.",
    @@ -2695,7 +2695,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days.",
    @@ -2717,7 +2717,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable Network Watcher for Azure subscriptions.",
    @@ -2737,7 +2737,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity.",
    @@ -2759,7 +2759,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service.",
    @@ -2781,7 +2781,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration. The features include: 1. Default Disk Encryption 2. Resilience, as Microsoft will managed the disk storage and move around if underlying hardware goes faulty 3. Reduction of costs over storage accounts",
    @@ -2803,7 +2803,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that OS disks (boot volumes) and data disks  (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE orServer Side Encryption (SSE).",
    @@ -2825,7 +2825,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK).",
    @@ -2845,7 +2845,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For added security, only install organization-approved extensions on VMs.",
    @@ -2867,7 +2867,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Install endpoint protection for all virtual machines.",
    @@ -2887,7 +2887,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "NOTE: This is a legacy recommendation. Managed Disks are encrypted by default and recommended for all new VM implementations. VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs",
    @@ -2909,7 +2909,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2931,7 +2931,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2953,7 +2953,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2975,7 +2975,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2997,7 +2997,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Key Vault contains object keys, secrets, and certificates. Accidental unavailability of a Key Vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the Key Vault objects. It is recommended the Key Vault be made recoverable by enabling the 'Do Not Purge' and 'Soft Delete' functions. This is in order to prevent loss of encrypted data, including storage accounts, SQL databases, and/or dependent services provided by Key Vault objects (Keys, Secrets, Certificates) etc. This may happen in the case of accidental deletion by a user or from disruptive activity by a malicious user. WARNING: A current limitation of the soft-delete feature across all Azure services is role assignments disappearing when Key Vault is deleted. All role assignments will need to be recreated after recovery.",
    @@ -3019,7 +3019,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "WARNING: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services.",
    @@ -3041,7 +3041,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys.",
    @@ -3063,7 +3063,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased.",
    @@ -3085,7 +3085,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented.",
    @@ -3107,7 +3107,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic.",
    @@ -3129,7 +3129,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS.",
    @@ -3151,7 +3151,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app.",
    @@ -3173,7 +3173,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords.",
    @@ -3195,7 +3195,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.",
    @@ -3217,7 +3217,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.",
    @@ -3239,7 +3239,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version.",
    @@ -3261,7 +3261,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to takeadvantage of security fixes, if any, and/or new functionalities of the newer version.",
    @@ -3283,7 +3283,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions.",
    @@ -3303,7 +3303,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions.",
    @@ -3323,7 +3323,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "10. Miscellaneous",
    +          "Section": "10 Miscellaneous",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion.",
    diff --git a/prowler/compliance/azure/cis_2.1_azure.json b/prowler/compliance/azure/cis_2.1_azure.json
    index 594b2ad851..e6b6a128cf 100644
    --- a/prowler/compliance/azure/cis_2.1_azure.json
    +++ b/prowler/compliance/azure/cis_2.1_azure.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators or appropriately delegated users to create new tenants.",
    @@ -32,7 +32,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data.   Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user.  Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed.",
    @@ -52,7 +52,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensures that two alternate forms of identification are provided before allowing a password reset.",
    @@ -72,7 +72,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Microsoft Entra ID Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy.",
    @@ -92,7 +92,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0.",
    @@ -112,7 +112,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that users are notified on their primary and secondary emails on password resets.",
    @@ -132,7 +132,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that all Global Administrators are notified if any other administrator resets their password.",
    @@ -154,7 +154,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators to provide consent for applications before use.",
    @@ -176,7 +176,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Allow users to provide consent for selected permissions when a request is coming from a verified publisher.",
    @@ -196,7 +196,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators to provide consent for the apps before use.",
    @@ -218,7 +218,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators or appropriately delegated users to register third-party applications.",
    @@ -240,7 +240,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Limit guest user permissions.",
    @@ -262,7 +262,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict invitations to users with specific administrative roles only.",
    @@ -282,7 +282,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Restrict access to the Microsoft Entra ID administration center to administrators only.  **NOTE**: This only affects access to the Entra ID administrator's web portal. This setting does not prohibit privileged users from using other methods such as Rest API or Powershell to obtain sensitive information from Microsoft Entra ID.",
    @@ -302,7 +302,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict access to group web interface in the Access Panel portal.",
    @@ -324,7 +324,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group creation to administrators only.",
    @@ -344,7 +344,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group management to administrators only.",
    @@ -366,7 +366,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict Microsoft 365 group creation to administrators only.",
    @@ -386,7 +386,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Joining or registering devices to Microsoft Entra ID should require Multi-factor authentication.",
    @@ -408,7 +408,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.",
    @@ -430,7 +430,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration.",
    @@ -450,7 +450,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Microsoft Entra ID.",
    @@ -472,7 +472,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This recommendation aims to maintain a balance between security and operational efficiency by ensuring that a minimum of 2 and a maximum of 4 users are assigned the Global Administrator role in Microsoft Entra ID. Having at least two Global Administrators ensures redundancy, while limiting the number to four reduces the risk of excessive privileged access.",
    @@ -494,7 +494,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -517,7 +517,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -540,7 +540,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults Security Defaults",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -561,7 +561,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.1 Security Defaults Security Defaults",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -584,7 +584,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -605,7 +605,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -626,7 +626,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -647,7 +647,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -668,7 +668,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -691,7 +691,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -712,7 +712,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "SubSection": "1.2 Conditional Access",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -735,7 +735,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -758,7 +758,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -781,7 +781,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -804,7 +804,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -827,7 +827,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -850,7 +850,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -873,7 +873,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -896,7 +896,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -919,7 +919,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -942,7 +942,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -965,7 +965,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -988,7 +988,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1011,7 +1011,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -1034,7 +1034,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1057,7 +1057,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1078,7 +1078,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1101,7 +1101,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1124,7 +1124,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1147,7 +1147,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1170,7 +1170,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1193,7 +1193,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1214,7 +1214,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.1 Microsoft Defender for Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1237,7 +1237,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Microsoft Defender",
    +          "Section": "2 Microsoft Defender",
               "SubSection": "2.2 Microsoft Defender for IoT",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -1260,7 +1260,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable data encryption in transit.",
    @@ -1282,7 +1282,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions.",
    @@ -1302,7 +1302,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The Rotation Reminder is an automatic reminder feature for a manual procedure.",
    @@ -1324,7 +1324,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For increased security, regenerate storage account access keys periodically.",
    @@ -1344,7 +1344,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.",
    @@ -1364,7 +1364,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Expire shared access signature tokens within an hour.",
    @@ -1386,7 +1386,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Disallowing public network access for a storage account overrides the public access settings for individual containers in that storage account for Azure Resource Manager Deployment Model storage accounts. Azure Storage accounts that use the classic deployment model will be retired on August 31, 2024.",
    @@ -1408,7 +1408,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed.",
    @@ -1430,7 +1430,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Azure services exception is enabled, the following services are granted access to the storage account: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor, and Azure SQL Data Warehouse (when registered in the subscription).",
    @@ -1452,7 +1452,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it.",
    @@ -1474,7 +1474,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability.  It is recommended that both Azure Containers with attached Blob Storage and standalone containers with Blob Storage be made recoverable by enabling the **soft delete** configuration. This is to save and recover data when blobs or blob snapshots are deleted.",
    @@ -1496,7 +1496,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Enable sensitive data encryption at rest using Customer Managed Keys (CMK) rather than Microsoft Managed keys.",
    @@ -1516,7 +1516,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1536,7 +1536,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1558,7 +1558,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2.",
    @@ -1578,7 +1578,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cross Tenant Replication in Azure allows data to be replicated across multiple Azure tenants. While this feature can be beneficial for data sharing and availability, it also poses a significant security risk if not properly managed. Unauthorized data access, data leakage, and compliance violations are potential risks. Disabling Cross Tenant Replication ensures that data is not inadvertently replicated across different tenant boundaries without explicit authorization.",
    @@ -1598,7 +1598,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Storage Accounts",
    +          "Section": "3 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Storage setting ‘Allow Blob Anonymous Access’ (aka allowBlobPublicAccess) controls whether anonymous access is allowed for blob data in a storage account. When this property is set to True, it enables public read access to blob data, which can be convenient for sharing data but may carry security risks. When set to False, it disallows public access to blob data, providing a more secure storage environment.",
    @@ -1620,7 +1620,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1643,7 +1643,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1666,7 +1666,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -1689,7 +1689,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1712,7 +1712,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1735,7 +1735,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.1 SQL Server - Auditing",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1758,7 +1758,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1781,7 +1781,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1804,7 +1804,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1827,7 +1827,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1850,7 +1850,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1873,7 +1873,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1896,7 +1896,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1917,7 +1917,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1940,7 +1940,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1963,7 +1963,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -1986,7 +1986,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2009,7 +2009,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.4 MySQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2032,7 +2032,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2055,7 +2055,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2078,7 +2078,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Database Services",
    +          "Section": "4 Database Services",
               "SubSection": "4.5 Cosmos DB",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -2099,7 +2099,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. Currently, 95 Azure resources support Azure Monitoring (See the more information section for a complete list), including Network Security Groups, Load Balancers, Key Vault, AD, Logic Apps, and CosmosDB. The content of these logs varies by resource type.  A number of back-end services were not configured to log and store Resource Logs for certain activities or for a sufficient length. It is crucial that monitoring is correctly configured to log all relevant activities and retain those logs for a sufficient length of time. Given that the mean time to detection in an enterprise is 240 days, a minimum retention period of two years is recommended.",
    @@ -2119,7 +2119,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft may refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads.",
    @@ -2141,7 +2141,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
    @@ -2164,7 +2164,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2187,7 +2187,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2210,7 +2210,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2233,7 +2233,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2256,7 +2256,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
    @@ -2279,7 +2279,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2302,7 +2302,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2325,7 +2325,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2348,7 +2348,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2371,7 +2371,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2394,7 +2394,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2417,7 +2417,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2440,7 +2440,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2463,7 +2463,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2486,7 +2486,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
    @@ -2509,7 +2509,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Logging and Monitoring",
    +          "Section": "5 Logging and Monitoring",
               "SubSection": "5.3 Configuring Application Insights. Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2532,7 +2532,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2554,7 +2554,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2576,7 +2576,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2598,7 +2598,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured.",
    @@ -2620,7 +2620,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days.",
    @@ -2642,7 +2642,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable Network Watcher for physical regions in Azure subscriptions.",
    @@ -2662,7 +2662,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Networking",
    +          "Section": "6 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity.",
    @@ -2684,7 +2684,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service.",
    @@ -2706,7 +2706,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration. The features include:  1) Default Disk Encryption 2) Resilience, as Microsoft will managed the disk storage and move around if underlying hardware goes faulty 3) Reduction of costs over storage accounts",
    @@ -2728,7 +2728,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption (SSE).",
    @@ -2750,7 +2750,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK).",
    @@ -2770,7 +2770,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For added security, only install organization-approved extensions on VMs.",
    @@ -2792,7 +2792,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Install endpoint protection for all virtual machines.",
    @@ -2812,7 +2812,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "**NOTE: This is a legacy recommendation. Managed Disks are encrypted by default and recommended for all new VM implementations.**  VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs.",
    @@ -2834,7 +2834,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Verify identities without MFA that can log in to a privileged virtual machine using separate login credentials. An adversary can leverage the access to move laterally and perform actions with the virtual machine's managed identity. Make sure the virtual machine only has necessary permissions, and revoke the admin-level permissions according to the least privileges principal",
    @@ -2856,7 +2856,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Virtual Machines",
    +          "Section": "7 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When **Secure Boot** and **vTPM** are enabled together, they provide a strong foundation for protecting your VM from boot attacks. For example, if an attacker attempts to replace the bootloader with a malicious version, Secure Boot will prevent the VM from booting. If the attacker is able to bypass Secure Boot and install a malicious bootloader, vTPM can be used to detect the intrusion and alert you.",
    @@ -2878,7 +2878,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2900,7 +2900,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2922,7 +2922,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2944,7 +2944,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -2966,7 +2966,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Key Vault contains object keys, secrets, and certificates. Accidental unavailability of a Key Vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the Key Vault objects.  It is recommended the Key Vault be made recoverable by enabling the Do Not Purge and Soft Delete functions. This is in order to prevent loss of encrypted data, including storage accounts, SQL databases, and/or dependent services provided by Key Vault objects (Keys, Secrets, Certificates) etc. This may happen in the case of accidental deletion by a user or from disruptive activity by a malicious user.  WARNING: A current limitation is that role assignments disappearing when Key Vault is deleted. All role assignments will need to be recreated after recovery.",
    @@ -2988,7 +2988,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "WARNING: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services.",
    @@ -3010,7 +3010,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys.",
    @@ -3032,7 +3032,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Key Vault",
    +          "Section": "8 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased.",
    @@ -3054,7 +3054,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented.",
    @@ -3076,7 +3076,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default.  Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic.",
    @@ -3098,7 +3098,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS.",
    @@ -3120,7 +3120,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering an App Service with Entra ID, the app will connect to other Azure services securely without the need for usernames and passwords.",
    @@ -3142,7 +3142,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.",
    @@ -3164,7 +3164,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version.",
    @@ -3186,7 +3186,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version.",
    @@ -3208,7 +3208,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.",
    @@ -3230,7 +3230,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "By default, Azure Functions, Web, and API Services  can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions.",
    @@ -3250,7 +3250,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions.",
    @@ -3270,7 +3270,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "10. Miscellaneous",
    +          "Section": "10 Miscellaneous",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion.",
    diff --git a/prowler/compliance/azure/cis_3.0_azure.json b/prowler/compliance/azure/cis_3.0_azure.json
    index 4175dd2a7e..0ba6c77444 100644
    --- a/prowler/compliance/azure/cis_3.0_azure.json
    +++ b/prowler/compliance/azure/cis_3.0_azure.json
    @@ -12,7 +12,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Require administrators or appropriately delegated users to create new tenants.",
    @@ -32,7 +32,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID has native and extended identity functionality allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities.",
    @@ -52,7 +52,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensures that two alternate forms of identification are provided before allowing a password reset.",
    @@ -72,7 +72,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The account lockout threshold determines how many failed login attempts are permitted prior to placing the account in a locked-out state and initiating a variable lockout duration.",
    @@ -92,7 +92,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The account lockout duration value determines how long an account retains the status of lockout, and therefore how long before a user can continue to attempt to login after passing the lockout threshold.",
    @@ -112,7 +112,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Microsoft Entra ID Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers.Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy.",
    @@ -132,7 +132,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0.",
    @@ -152,7 +152,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that users are notified on their primary and alternate emails on password resets.",
    @@ -172,7 +172,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that all Global Administrators are notified if any other administrator resets their password.",
    @@ -194,7 +194,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Require administrators to provide consent for applications before use.",
    @@ -216,7 +216,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Allow users to provide consent for selected permissions when a request is coming from a verified publisher.",
    @@ -238,7 +238,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Require administrators or appropriately delegated users to register third-party applications.",
    @@ -260,7 +260,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Limit guest user permissions.",
    @@ -282,7 +282,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Restrict invitations to users with specific administrative roles only.",
    @@ -302,7 +302,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Restrict access to the Microsoft Entra ID administration center to administrators only.**NOTE**: This only affects access to the Entra ID administrator's web portal. This setting does not prohibit privileged users from using other methods such as Rest API or Powershell to obtain sensitive information from Microsoft Entra ID.",
    @@ -322,7 +322,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict access to group web interface in the Access Panel portal.",
    @@ -344,7 +344,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group creation to administrators only.",
    @@ -364,7 +364,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict security group management to administrators only.",
    @@ -386,7 +386,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Restrict Microsoft 365 group creation to administrators only.",
    @@ -406,7 +406,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "**NOTE:** This recommendation is only relevant if your subscription is using Per-User MFA. If your organization is licensed to use Conditional Access, the preferred method of requiring MFA to join devices to Entra ID is to use a Conditional Access policy (see additional information below for link).Joining or registering devices to Microsoft Entra ID should require multi-factor authentication.",
    @@ -428,7 +428,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.",
    @@ -450,7 +450,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration.",
    @@ -470,7 +470,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Microsoft Entra ID.",
    @@ -492,7 +492,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    +          "Section": "2 Identity",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This recommendation aims to maintain a balance between security and operational efficiency by ensuring that a minimum of 2 and a maximum of 4 users are assigned the Global Administrator role in Microsoft Entra ID. Having at least two Global Administrators ensures redundancy, while limiting the number to four reduces the risk of excessive privileged access.",
    @@ -514,8 +514,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.1. Security Defaults (Per-User MFA)",
    +          "Section": "2 Identity",
    +          "SubSection": "2.1 Security Defaults (Per-User MFA)",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "[**IMPORTANT - Please read the section overview:** If your organization pays for Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, or F5, and EM&S E3 or E5 licenses) and **CAN** use Conditional Access, ignore the recommendations in this section and proceed to the Conditional Access section.]Security defaults in Microsoft Entra ID make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks.Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal.",
    @@ -537,8 +537,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.1. Security Defaults (Per-User MFA)",
    +          "Section": "2 Identity",
    +          "SubSection": "2.1 Security Defaults (Per-User MFA)",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "[**IMPORTANT - Please read the section overview:** If your organization pays for Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, or F5, and EM&S E3 or E5 licenses) and **CAN** use Conditional Access, ignore the recommendations in this section and proceed to the Conditional Access section.]Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. These include custom created objects or built-in roles such as;- Service Co-Administrators- Subscription Owners- Contributors",
    @@ -560,8 +560,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.1. Security Defaults (Per-User MFA)",
    +          "Section": "2 Identity",
    +          "SubSection": "2.1 Security Defaults (Per-User MFA)",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "[**IMPORTANT - Please read the section overview:** If your organization pays for Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, or F5, and EM&S E3 or E5 licenses) and **CAN** use Conditional Access, ignore the recommendations in this section and proceed to the Conditional Access section.]Enable multi-factor authentication for all non-privileged users.",
    @@ -581,8 +581,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.1. Security Defaults (Per-User MFA)",
    +          "Section": "2 Identity",
    +          "SubSection": "2.1 Security Defaults (Per-User MFA)",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "[**IMPORTANT - Please read the section overview:** If your organization pays for Microsoft Entra ID licensing (included in Microsoft 365 E3, E5, or F5, and EM&S E3 or E5 licenses) and **CAN** use Conditional Access, ignore the recommendations in this section and proceed to the Conditional Access section.]Do not allow users to remember multi-factor authentication on devices.",
    @@ -604,8 +604,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID Conditional Access allows an organization to configure `Named locations` and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization.",
    @@ -625,8 +625,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "**CAUTION**: If these policies are created without first auditing and testing the result, misconfiguration can potentially lock out administrators or create undesired access issues.Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined.",
    @@ -646,8 +646,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Conditional Access Policies can be used to prevent the Device code authentication flow. Device code flow should be permitted only for users that regularly perform duties that explicitly require the use of Device Code to authenticate, such as utilizing Azure with PowerShell.",
    @@ -667,8 +667,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login.",
    @@ -688,8 +688,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins.",
    @@ -709,8 +709,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Entra ID tracks the behavior of sign-in events. If the Entra ID domain is licensed with P2, the sign-in behavior can be used as a detection mechanism for additional scrutiny during the sign-in event. If this policy is set up, then Risky Sign-in events will prompt users to use multi-factor authentication (MFA) tokens on login for additional verification.",
    @@ -732,8 +732,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "This recommendation ensures that users accessing the Windows Azure Service Management API (i.e. Azure Powershell, Azure CLI, Azure Resource Manager API, etc.) are required to use multi-factor authentication (MFA) credentials when accessing resources through the Windows Azure Service Management API.",
    @@ -755,8 +755,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Identity",
    -          "SubSection": "2.2. Conditional Access",
    +          "Section": "2 Identity",
    +          "SubSection": "2.2 Conditional Access",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "This recommendation ensures that users accessing Microsoft Admin Portals (i.e. Microsoft 365 Admin, Microsoft 365 Defender, Exchange Admin Center, Azure Portal, etc.) are required to use multi-factor authentication (MFA) credentials when logging into an Admin Portal.",
    @@ -778,8 +778,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the latest OS patches for all virtual machines are applied.",
    @@ -801,8 +801,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The Microsoft Cloud Security Benchmark (or 'MCSB') is an Azure Policy Initiative containing many security policies to evaluate resource configuration against best practice recommendations. If a policy in the MCSB is set with effect type `Disabled`, it is not evaluated and may prevent administrators from being informed of valuable security recommendations.",
    @@ -824,8 +824,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable security alert emails to subscription owners.",
    @@ -847,8 +847,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address.",
    @@ -870,8 +870,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enables emailing security alerts to the subscription owner or other designated security contact.",
    @@ -891,8 +891,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "An organization's attack surface is the collection of assets with a public network identifier or URI that an external threat actor can see or access from outside your cloud. It is the set of points on the boundary of a system, a system element, system component, or an environment where an attacker can try to enter, cause an effect on, or extract data from, that system, system element, system component, or environment. The larger the attack surface, the harder it is to protect.This tool can be configured to scan your organization's online infrastructure such as specified domains, hosts, CIDR blocks, and SSL certificates, and store them in an Inventory. Inventory items can be added, reviewed, approved, and removed, and may contain enrichments ('insights') and additional information collected from the tool's different scan engines and open-source intelligence sources.A Defender EASM workspace will generate an Inventory of publicly exposed assets by crawling and scanning the internet using _Seeds_ you provide when setting up the tool. Seeds can be FQDNs, IP CIDR blocks, and WHOIS records.Defender EASM will generate Insights within 24-48 hours after Seeds are provided, and these insights include vulnerability data (CVEs), ports and protocols, and weak or expired SSL certificates that could be used by an attacker for reconnaisance or exploitation.Results are classified High/Medium/Low and some of them include proposed mitigations.",
    @@ -914,8 +914,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1. Microsoft Defender For Cloud",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "[**NOTE:** As of August 1, 2023 customers with an existing subscription to Defender for DNS can continue to use the service, but new subscribers will receive alerts about suspicious DNS activity as part of Defender for Servers P2.]Microsoft Defender for DNS scans all network traffic exiting from within a subscription.",
    @@ -937,8 +937,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.1 Microsoft Cloud Security Posture Management (CSPM)",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable automatic provisioning of the monitoring agent to collect security data.**DEPRECATION PLANNED:** The Log Analytics Agent is slated for deprecation in August 2024. The Microsoft Defender for Endpoint agent, in tandem with new agentless capabilities will be providing replacement functionality. More detail is available here: [https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/microsoft-defender-for-cloud-strategy-and-plan-towards-log/ba-p/3883341](https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/microsoft-defender-for-cloud-strategy-and-plan-towards-log/ba-p/3883341).",
    @@ -960,8 +960,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.1 Microsoft Cloud Security Posture Management (CSPM)",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud.",
    @@ -983,8 +983,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.3. Defender Plan: Servers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
    @@ -1006,8 +1006,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.3. Defender Plan: Servers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Enable vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines.",
    @@ -1027,8 +1027,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.3. Defender Plan: Servers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "The Endpoint protection component enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud.**IMPORTANT:** When enabling integration between DfE & DfC it needs to be taken into account that this will have some side effects that may be undesirable.1. For server 2019 & above if defender is installed (default for these server SKUs) this will trigger a deployment of the new unified agent and link to any of the extended configuration in the Defender portal.1. If the new unified agent is required for server SKUs of Win 2016 or Linux and lower there is additional integration that needs to be switched on and agents need to be aligned.",
    @@ -1048,8 +1048,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.3. Defender Plan: Servers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Using disk snapshots, the agentless scanner scans for installed software, vulnerabilities, and plain text secrets.",
    @@ -1069,8 +1069,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.3. Defender Plan: Servers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "File Integrity Monitoring (FIM) is a feature that monitors critical system files in Windows or Linux for potential signs of attack or compromise.",
    @@ -1092,8 +1092,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.4. Defender Plan: Containers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. The following services will be enabled for container instances:- Defender agent in Azure- Azure Policy for Kubernetes- Agentless discovery for Kubernetes- Agentless container vulnerability assessment",
    @@ -1113,8 +1113,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.4. Defender Plan: Containers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable automatic discovery and configuration scanning of the Microsoft Kubernetes clusters.",
    @@ -1134,8 +1134,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.4. Defender Plan: Containers",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable automatic vulnerability management for images stored in ACR or running in AKS clusters.",
    @@ -1157,8 +1157,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.5. Defender Plan: Storage",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
    @@ -1180,8 +1180,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.6. Defender Plan: App Service",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
    @@ -1203,8 +1203,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.7. Defender Plan: Databases",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources.",
    @@ -1226,8 +1226,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.7. Defender Plan: Databases",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
    @@ -1249,8 +1249,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.7. Defender Plan: Databases",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Managed Instance Azure SQL databases, providing threat intelligence, anomaly detection, and behavior analytics in Microsoft Defender for Cloud.",
    @@ -1272,8 +1272,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.7. Defender Plan: Databases",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in Microsoft Defender for Cloud.",
    @@ -1295,8 +1295,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.8. Defender Plan: Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
    @@ -1318,8 +1318,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.1.9. Defender Plan: Resource Manager",
    +          "Section": "3 Security",
    +          "SubSection": "3.1 Microsoft Defender For Cloud",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal.",
    @@ -1341,8 +1341,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.2. Microsoft Defender for IoT",
    +          "Section": "3 Security",
    +          "SubSection": "3.2 Microsoft Defender for IoT",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization.",
    @@ -1364,8 +1364,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -1387,8 +1387,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -1410,8 +1410,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -1433,8 +1433,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set.",
    @@ -1456,8 +1456,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Key Vault contains object keys, secrets, and certificates. Accidental unavailability of a Key Vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the Key Vault objects.It is recommended the Key Vault be made recoverable by enabling the 'Do Not Purge' and 'Soft Delete' functions. This is in order to prevent loss of encrypted data, including storage accounts, SQL databases, and/or dependent services provided by Key Vault objects (Keys, Secrets, Certificates) etc. This may happen in the case of accidental deletion by a user or from disruptive activity by a malicious user.**NOTE:** In February 2025, Microsoft will enable soft-delete protection on all key vaults, and users will no longer be able to opt out of or turn off soft-delete. **WARNING:** A current limitation is that role assignments disappearing when Key Vault is deleted. All role assignments will need to be recreated after recovery.",
    @@ -1479,8 +1479,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The recommended way to access Key Vaults is to use the Azure Role-Based Access Control (RBAC) permissions model.Azure RBAC is an authorization system built on Azure Resource Manager that provides fine-grained access management of Azure resources. It allows users to manage Key, Secret, and Certificate permissions. It provides one place to manage all permissions across all key vaults.",
    @@ -1502,8 +1502,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys.",
    @@ -1525,8 +1525,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Security",
    -          "SubSection": "3.3. Key Vault",
    +          "Section": "3 Security",
    +          "SubSection": "3.3 Key Vault",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased.",
    @@ -1548,7 +1548,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable data encryption in transit.",
    @@ -1568,7 +1568,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions.",
    @@ -1590,7 +1590,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure.",
    @@ -1612,7 +1612,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For increased security, regenerate storage account access keys periodically.",
    @@ -1632,7 +1632,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Expire shared access signature tokens within an hour.",
    @@ -1654,7 +1654,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Disallowing public network access for a storage account overrides the public access settings for individual containers in that storage account for Azure Resource Manager Deployment Model storage accounts. Azure Storage accounts that use the classic deployment model will be retired on August 31, 2024.",
    @@ -1676,7 +1676,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed.",
    @@ -1698,7 +1698,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "_NOTE:_ This recommendation assumes that the `Public network access` parameter is set to `Enabled from selected virtual networks and IP addresses`. Please ensure the prerequisite recommendation has been implemented before proceeding: - Ensure Default Network Access Rule for Storage Accounts is Set to DenySome Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. If the `Allow Azure services on the trusted services list to access this storage account` exception is enabled, the following services are granted access to the storage account: Azure Backup, Azure Data Box, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure File Sync, Azure HDInsight, Azure Import/Export, Azure Monitor, Azure Networking Services, and Azure Site Recovery (when registered in the subscription).",
    @@ -1720,7 +1720,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it.",
    @@ -1742,7 +1742,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability.It is recommended that both Azure Containers with attached Blob Storage and standalone containers with Blob Storage be made recoverable by enabling the **soft delete** configuration. This is to save and recover data when blobs or blob snapshots are deleted.",
    @@ -1764,7 +1764,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Enable sensitive data encryption at rest using Customer Managed Keys (CMK) rather than Microsoft Managed keys.",
    @@ -1784,7 +1784,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.",
    @@ -1804,7 +1804,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1824,7 +1824,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.",
    @@ -1846,7 +1846,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2.",
    @@ -1866,7 +1866,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cross Tenant Replication in Azure allows data to be replicated across multiple Azure tenants. While this feature can be beneficial for data sharing and availability, it also poses a significant security risk if not properly managed. Unauthorized data access, data leakage, and compliance violations are potential risks. Disabling Cross Tenant Replication ensures that data is not inadvertently replicated across different tenant boundaries without explicit authorization.",
    @@ -1886,7 +1886,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Storage Accounts",
    +          "Section": "4 Storage Accounts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Storage setting ‘Allow Blob Anonymous Access’ (aka 'allowBlobPublicAccess') controls whether anonymous access is allowed for blob data in a storage account. When this property is set to True, it enables public read access to blob data, which can be convenient for sharing data but may carry security risks. When set to False, it disallows public access to blob data, providing a more secure storage environment.",
    @@ -1908,8 +1908,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable auditing on SQL Servers.",
    @@ -1931,8 +1931,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP).",
    @@ -1954,8 +1954,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties.With TDE, data is encrypted at rest with a symmetric key (called the database encryption key) stored in the database or data warehouse distribution. To protect this data encryption key (DEK) in the past, only a certificate that the Azure SQL Service managed could be used. Now, with Customer-managed key support for TDE, the DEK can be protected with an asymmetric key that is stored in the Azure Key Vault. The Azure Key Vault is a highly available and scalable cloud-based key store which offers central key management, leverages FIPS 140-2 Level 2 validated hardware security modules (HSMs), and allows separation of management of keys and data for additional security.Based on business needs or criticality of data/databases hosted on a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key).",
    @@ -1977,8 +1977,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Use Microsoft Entra authentication for authentication with SQL Database to manage credentials in a single place.",
    @@ -2000,8 +2000,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable Transparent Data Encryption on every SQL server.",
    @@ -2023,8 +2023,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "SQL Server Audit Retention should be configured to be greater than 90 days.",
    @@ -2044,8 +2044,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.1. Azure SQL Database",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.1 Azure SQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Disabling public network access restricts the service from accessing public networks.",
    @@ -2067,8 +2067,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable `require_secure_transport` on `PostgreSQL flexible servers`.",
    @@ -2090,8 +2090,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable `log_checkpoints` on `PostgreSQL flexible servers`.",
    @@ -2113,8 +2113,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable connection throttling on `PostgreSQL flexible servers`.",
    @@ -2136,8 +2136,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure `logfiles.retention_days` on `PostgreSQL flexible servers` is set to an appropriate value.",
    @@ -2159,8 +2159,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Disable access from Azure services to `PostgreSQL flexible server`.",
    @@ -2182,8 +2182,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable `log_connections` on `PostgreSQL single servers`.**NOTE:** This recommendation currently only applies to Single Server, not Flexible Server. See additional information below for details about the planned retirement of Azure PostgreSQL Single Server.",
    @@ -2205,8 +2205,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable `log_disconnections` on `PostgreSQL Servers`.**NOTE:** This recommendation currently only applies to Single Server, not Flexible Server. See additional information below for details about the planned retirement of Azure PostgreSQL Single Server.",
    @@ -2226,8 +2226,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.2. Azure SQL Database for PostgreSQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.2 Azure SQL Database for PostgreSQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled.**NOTE:** This recommendation currently only applies to Single Server, not Flexible Server. See additional information below for details about the planned retirement of Azure PostgreSQL Single Server.",
    @@ -2249,8 +2249,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.3. Azure for MySQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.3 Azure for MySQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable `require_secure_transport` on `MySQL flexible servers`.",
    @@ -2270,8 +2270,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.3. Azure for MySQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.3 Azure for MySQL",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure `tls_version` on `MySQL flexible servers` is set to use TLS version 1.2 or higher.",
    @@ -2293,8 +2293,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.3. Azure for MySQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.3 Azure for MySQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable `audit_log_enabled` on `MySQL flexible servers`.",
    @@ -2316,8 +2316,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.3. Azure for MySQL",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.3 Azure for MySQL",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Set `audit_log_events` to include `CONNECTION` on `MySQL flexible servers`.",
    @@ -2339,8 +2339,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.4. Azure Cosmos DB",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.4 Azure Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint.",
    @@ -2362,8 +2362,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.4. Azure Cosmos DB",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.4 Azure Cosmos DB",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Private endpoints limit network traffic to approved sources.",
    @@ -2385,8 +2385,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Database Services",
    -          "SubSection": "5.4. Azure Cosmos DB",
    +          "Section": "5 Database Services",
    +          "SubSection": "5.4 Azure Cosmos DB",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Cosmos DB can use tokens or Entra ID for client authentication which in turn will use Azure RBAC for authorization. Using Entra ID is significantly more secure because Entra ID handles the credentials and allows for MFA and centralized management, and the Azure RBAC is better integrated with the rest of Azure.",
    @@ -2406,7 +2406,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    +          "Section": "6 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. Currently, 95 Azure resources support Azure Monitoring (See the more information section for a complete list), including Network Security Groups, Load Balancers, Key Vault, AD, Logic Apps, and CosmosDB. The content of these logs varies by resource type.A number of back-end services were not configured to log and store Resource Logs for certain activities or for a sufficient length. It is crucial that monitoring is correctly configured to log all relevant activities and retain those logs for a sufficient length of time. Given that the mean time to detection in an enterprise is 240 days, a minimum retention period of two years is recommended.",
    @@ -2426,7 +2426,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    +          "Section": "6 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft may refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads.",
    @@ -2448,8 +2448,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Enable Diagnostic settings for exporting activity logs.Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment.",
    @@ -2471,8 +2471,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "**Prerequisite**: A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.'The diagnostic setting should be configured to log the appropriate activities from the control/management plane.",
    @@ -2494,8 +2494,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK).",
    @@ -2517,8 +2517,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available.",
    @@ -2540,8 +2540,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that network flow logs are captured and fed into a central log analytics workspace.",
    @@ -2563,8 +2563,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.1. Configuring Diagnostic Settings",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.1 Configuring Diagnostic Settings",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged.",
    @@ -2586,8 +2586,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Create Policy Assignment event.",
    @@ -2609,8 +2609,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Delete Policy Assignment event.",
    @@ -2632,8 +2632,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an Activity Log Alert for the Create or Update Network Security Group event.",
    @@ -2655,8 +2655,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Delete Network Security Group event.",
    @@ -2678,8 +2678,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Create or Update Security Solution event.",
    @@ -2701,8 +2701,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Delete Security Solution event.",
    @@ -2724,8 +2724,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Create or Update SQL Server Firewall Rule event.",
    @@ -2747,8 +2747,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the 'Delete SQL Server Firewall Rule.",
    @@ -2770,8 +2770,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Create or Update Public IP Addresses rule.",
    @@ -2793,8 +2793,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    -          "SubSection": "6.2. Monitoring using Activity Log Alerts",
    +          "Section": "6 Logging and Monitoring",
    +          "SubSection": "6.2 Monitoring using Activity Log Alerts",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Create an activity log alert for the Delete Public IP Address rule.",
    @@ -2816,7 +2816,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Logging and Monitoring",
    +          "Section": "6 Logging and Monitoring",
               "SubSection": "6.3. Configuring Application Insights",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
    @@ -2839,7 +2839,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2861,7 +2861,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2883,7 +2883,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required.",
    @@ -2905,7 +2905,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured.",
    @@ -2927,7 +2927,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days.",
    @@ -2949,7 +2949,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enable Network Watcher for physical regions in Azure subscriptions.",
    @@ -2969,7 +2969,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. Networking",
    +          "Section": "7 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity.",
    @@ -2991,7 +2991,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service.",
    @@ -3013,7 +3013,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration.The features include: 1) Default Disk Encryption2) Resilience, as Microsoft will managed the disk storage and move around if underlying hardware goes faulty3) Reduction of costs over storage accounts",
    @@ -3035,7 +3035,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys).Customer Managed keys can be either ADE or Server Side Encryption (SSE).",
    @@ -3057,7 +3057,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK).",
    @@ -3077,7 +3077,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Virtual Machine Disks and snapshots can be configured to allow access from different network resources.",
    @@ -3097,7 +3097,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Data Access Authentication Mode provides a method of uploading or exporting Virtual Machine Disks.",
    @@ -3117,7 +3117,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For added security, only install organization-approved extensions on VMs.",
    @@ -3139,7 +3139,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Install endpoint protection for all virtual machines.",
    @@ -3159,7 +3159,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "**NOTE: This is a legacy recommendation. Managed Disks are encrypted by default and recommended for all new VM implementations.**VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs.",
    @@ -3181,7 +3181,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Verify identities without MFA that can log in to a privileged virtual machine using separate login credentials. An adversary can leverage the access to move laterally and perform actions with the virtual machine's managed identity. Make sure the virtual machine only has necessary permissions, and revoke the admin-level permissions according to the least privileges principal",
    @@ -3203,7 +3203,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Virtual Machines",
    +          "Section": "8 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When **Secure Boot** and **vTPM** are enabled together, they provide a strong foundation for protecting your VM from boot attacks. For example, if an attacker attempts to replace the bootloader with a malicious version, Secure Boot will prevent the VM from booting. If the attacker is able to bypass Secure Boot and install a malicious bootloader, vTPM can be used to detect the intrusion and alert you.",
    @@ -3225,7 +3225,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Azure App Service allows apps to run under both HTTP and HTTPS by default. Apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic.",
    @@ -3247,7 +3247,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented.",
    @@ -3269,7 +3269,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "By default, App Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Services.If FTPS is not expressly required for the App, the recommended setting is `Disabled.`",
    @@ -3291,7 +3291,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS.",
    @@ -3313,7 +3313,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering an App Service with Entra ID, the app will connect to other Azure services securely without the need for usernames and passwords.",
    @@ -3333,7 +3333,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Basic Authentication provides the ability to create identities and authentication for an App Service without a centralized Identity Provider. For a more effective, capable, and secure solution for Identity, Authentication, Authorization, and Accountability, a centralized Identity Provider such as Entra ID is strongly advised.",
    @@ -3355,7 +3355,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, older versions of PHP may be deprecated and no longer supported. Using a supported version of PHP for app services is recommended to avoid potential unpatched vulnerabilities.",
    @@ -3377,7 +3377,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, older versions of Python may be deprecated and no longer supported. Using a supported version of Python for app services is recommended to avoid potential unpatched vulnerabilities.",
    @@ -3399,7 +3399,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Periodically, older versions of Java may be deprecated and no longer supported. Using a supported version of Java for app services is recommended to avoid potential unpatched vulnerabilities.",
    @@ -3421,7 +3421,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.",
    @@ -3441,7 +3441,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions.",
    @@ -3461,7 +3461,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9. AppService",
    +          "Section": "9 AppService",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Remote Debugging allows Azure App Service to be debugged in real-time directly on the Azure environment. When remote debugging is enabled, it opens a communication channel that could potentially be exploited by unauthorized users if not properly secured.",
    @@ -3481,7 +3481,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "10. Miscellaneous",
    +          "Section": "10 Miscellaneous",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion.",
    diff --git a/prowler/compliance/gcp/cis_2.0_gcp.json b/prowler/compliance/gcp/cis_2.0_gcp.json
    index abc6238a09..6ef4d575e4 100644
    --- a/prowler/compliance/gcp/cis_2.0_gcp.json
    +++ b/prowler/compliance/gcp/cis_2.0_gcp.json
    @@ -10,7 +10,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Use corporate login credentials instead of personal accounts, such as Gmail accounts.",
    @@ -29,7 +29,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Setup multi-factor authentication for Google Cloud Platform accounts.",
    @@ -48,7 +48,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Setup Security Key Enforcement for Google Cloud Platform admin accounts.",
    @@ -69,7 +69,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. API keys are always at risk because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API keys to use (call) only APIs required by an application.",
    @@ -90,7 +90,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. If they are in use it is recommended to rotate API keys every 90 days.",
    @@ -111,7 +111,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. Unused keys with their permissions in tact may still exist within a project. Keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to use standard authentication flow instead.",
    @@ -132,7 +132,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that Essential Contacts is configured to designate email addresses for Google Cloud services to notify of important technical or security information.",
    @@ -153,7 +153,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud Key Management Service stores cryptographic keys in a hierarchical structure designed for useful and elegant access control management.   The format for the rotation schedule depends on the client library that is used. For the gcloud command-line tool, the next rotation time must be in `ISO` or `RFC3339` format, and the rotation period must be in the form `INTEGERUNIT`, where units can be one of seconds (s), minutes (m), hours (h) or days (d).",
    @@ -174,7 +174,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the IAM policy on Cloud KMS `cryptokeys` should restrict anonymous and/or public access.",
    @@ -195,7 +195,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "When you use Dataproc, cluster and job data is stored on Persistent Disks (PDs) associated with the Compute Engine VMs in your cluster and in a Cloud Storage staging bucket. This PD and bucket data is encrypted using a Google-generated data encryption key (DEK) and key encryption key (KEK). The CMEK feature allows you to create, use, and revoke the key encryption key (KEK). Google still controls the data encryption key (DEK).",
    @@ -216,7 +216,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to assign the `Service Account User (iam.serviceAccountUser)` and `Service Account Token Creator (iam.serviceAccountTokenCreator)` roles to a user for a specific service account rather than assigning the role to a user at project level.",
    @@ -237,7 +237,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning KMS related roles to users.",
    @@ -256,7 +256,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. In this case, unrestricted keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API key usage to trusted hosts, HTTP referrers and apps. It is recommended to use the more secure standard authentication flow instead.",
    @@ -277,7 +277,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning service-account related roles to users.",
    @@ -298,7 +298,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "A service account is a special Google account that belongs to an application or a VM, instead of to an individual end-user. The application uses the service account to call the service's Google API so that users aren't directly involved. It's recommended not to use admin access for ServiceAccount.",
    @@ -319,7 +319,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "User managed service accounts should not have user-managed keys.",
    @@ -340,7 +340,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Service Account keys consist of a key ID (Private_key_Id) and Private key, which are used to sign programmatic requests users make to Google cloud services accessible to that particular service account. It is recommended that all Service Account keys are regularly rotated.",
    @@ -359,7 +359,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Google Cloud Functions allow you to host serverless code that is executed when an event is triggered, without the requiring the management a host operating system. These functions can also store environment variables to be used by the code that may contain authentication or other information that needs to remain confidential.",
    @@ -380,7 +380,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP Access Approval enables you to require your organizations' explicit approval whenever Google support try to access your projects. You can then select users within your organization who can approve these requests through giving them a security role in IAM. All access requests display which Google Employee requested them in an email or Pub/Sub message that you can choose to Approve. This adds an additional control and logging of who in your organization approved/denied these requests.",
    @@ -401,7 +401,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.",
    @@ -422,7 +422,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In order to prevent unnecessary project ownership assignments to users/service-accounts and further misuses of projects and resources, all `roles/Owner` assignments should be monitored.  Members (users/Service-Accounts) with a role assignment to primitive role `roles/Owner` are project owners.  The project owner has all the privileges on the project the role belongs to. These are summarized below: - All viewer permissions on all GCP Services within the project - Permissions for actions that modify the state of all GCP services within the project - Manage roles and permissions for a project and all resources within the project - Set up billing for a project  Granting the owner role to a member (user/Service-Account) will allow that member to modify the Identity and Access Management (IAM) policy. Therefore, grant the owner role only if the member has a legitimate purpose to manage the IAM policy. This is because the project IAM policy contains sensitive access control data. Having a minimal set of users allowed to manage IAM policy will simplify any auditing that may be necessary.",
    @@ -443,7 +443,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Logging enabled on a HTTPS Load Balancer will show all network traffic and its destination.",
    @@ -464,7 +464,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that Cloud Audit Logging is configured to track all admin activities and read, write access to user data.",
    @@ -485,7 +485,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cloud DNS logging records the queries from the name servers within your VPC to Stackdriver. Logged queries can come from Compute Engine VMs, GKE containers, or other GCP resources provisioned within the VPC.",
    @@ -506,7 +506,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling retention policies on log buckets will protect logs stored in cloud storage buckets from being overwritten or accidentally deleted. It is recommended to set up retention policies and configure Bucket Lock on all storage buckets that are used as log sinks.",
    @@ -527,7 +527,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to create a sink that will export copies of all the log entries. This can help aggregate logs from multiple projects and export them to a Security Information and Event Management (SIEM).",
    @@ -548,7 +548,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud Platform (GCP) services write audit log entries to the Admin Activity and Data Access logs to help answer the questions of, \"who did what, where, and when?\" within GCP projects.  Cloud audit logging records information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by GCP services. Cloud audit logging provides a history of GCP API calls for an account, including API calls made via the console, SDKs, command-line tools, and other GCP services.",
    @@ -569,7 +569,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Cloud Storage Bucket IAM changes.",
    @@ -590,7 +590,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for changes to Identity and Access Management (IAM) role creation, deletion and updating activities.",
    @@ -611,7 +611,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for SQL instance configuration changes.",
    @@ -632,7 +632,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network changes.",
    @@ -651,7 +651,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "GCP Access Transparency provides audit logs for all actions that Google personnel take in your Google Cloud resources.",
    @@ -672,7 +672,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) Network Firewall rule changes.",
    @@ -693,7 +693,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network route changes.",
    @@ -714,7 +714,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In order to prevent use of legacy networks, a project should not have a legacy network configured. As of now, Legacy Networks are gradually being phased out, and you can no longer create projects with them. This recommendation is to check older projects to ensure that they are not using Legacy Networks.",
    @@ -735,7 +735,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cloud Domain Name System (DNS) is a fast, reliable and cost-effective domain name system that powers millions of domains on the internet. Domain Name System Security Extensions (DNSSEC) in Cloud DNS enables domain owners to take easy steps to protect their domains against DNS hijacking and man-in-the-middle and other attacks.",
    @@ -756,7 +756,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow users to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.  Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the Internet to a VPC or VM instance using `RDP` on `Port 3389` can be avoided.",
    @@ -777,7 +777,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.  DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
    @@ -798,7 +798,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.  DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
    @@ -819,7 +819,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow the user to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.  Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, only an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the internet to VPC or VM instance using `SSH` on `Port 22` can be avoided.",
    @@ -840,7 +840,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "To prevent use of `default` network, a project should not have a `default` network.",
    @@ -861,7 +861,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Flow Logs is a feature that enables users to capture information about the IP traffic going to and from network interfaces in the organization's VPC Subnets. Once a flow log is created, the user can view and retrieve its data in Stackdriver Logging. It is recommended that Flow Logs be enabled for every business-critical VPC subnet.",
    @@ -880,7 +880,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Secure Sockets Layer (SSL) policies determine what port Transport Layer Security (TLS) features clients are permitted to use when connecting to load balancers. To prevent usage of insecure features, SSL policies should use (a) at least TLS 1.2 with the MODERN profile; or (b) the RESTRICTED profile, because it effectively requires clients to use TLS 1.2 regardless of the chosen minimum TLS version; or (3) a CUSTOM profile that does not support any of the following features:  ``` TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA ```",
    @@ -899,7 +899,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "IAP authenticates the user requests to your apps via a Google single sign in. You can then manage these users with permissions to control access. It is recommended to use both IAP permissions and firewalls to restrict this access to your apps with sensitive information.",
    @@ -920,7 +920,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Interacting with a serial port is often referred to as the serial console, which is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support.  If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. Therefore interactive serial console support should be disabled.",
    @@ -941,7 +941,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to use Instance specific SSH key(s) instead of using common/shared project-wide SSH key(s) to access Instances.",
    @@ -962,7 +962,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "To defend against advanced threats and ensure that the boot loader and firmware on your VMs are signed and untampered, it is recommended that Compute instances are launched with Shielded VM enabled.",
    @@ -983,7 +983,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling OS login binds SSH certificates to IAM users and facilitates effective SSH certificate management.",
    @@ -1004,7 +1004,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Compute instances should not be configured to have external IP addresses.",
    @@ -1025,7 +1025,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud encrypts data at-rest and in-transit, but customer data must be decrypted for processing. Confidential Computing is a breakthrough technology which encrypts data in-use—while it is being processed. Confidential Computing environments keep data encrypted in memory and elsewhere outside the central processing unit (CPU).   Confidential VMs leverage the Secure Encrypted Virtualization (SEV) feature of AMD EPYC™ CPUs. Customer data will stay encrypted while it is used, indexed, queried, or trained on. Encryption keys are generated in hardware, per VM, and not exportable. Thanks to built-in hardware optimizations of both performance and security, there is no significant performance penalty to Confidential Computing workloads.",
    @@ -1046,7 +1046,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to configure your instance to not use the default Compute Engine service account because it has the Editor role on the project.",
    @@ -1067,7 +1067,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account `Compute Engine default service account` with Scope `Allow full access to all Cloud APIs`.",
    @@ -1088,7 +1088,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets.  Forwarding of data packets should be disabled to prevent data loss or information disclosure.",
    @@ -1107,7 +1107,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In order to maintain the highest level of security all connections to an application should be secure by default.",
    @@ -1128,7 +1128,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Customer-Supplied Encryption Keys (CSEK) are a feature in Google Cloud Storage and Google Compute Engine. If you supply your own encryption keys, Google uses your key to protect the Google-generated keys used to encrypt and decrypt your data. By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.",
    @@ -1147,7 +1147,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Google Cloud Virtual Machines have the ability via an OS Config agent API to periodically (about every 10 minutes) report OS inventory data. A patch compliance API periodically reads this data, and cross references metadata to determine if the latest updates are installed.  This is not the only Patch Management solution available to your organization and you should weigh your needs before committing to using this method.",
    @@ -1168,7 +1168,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Storage",
    +          "Section": "5 Storage",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that IAM policy on Cloud Storage bucket does not allows anonymous or public access.",
    @@ -1189,7 +1189,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Storage",
    +          "Section": "5 Storage",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that uniform bucket-level access is enabled on Cloud Storage buckets.",
    @@ -1210,7 +1210,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to have all SQL database instances set to enable automated backups.",
    @@ -1231,7 +1231,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to configure Second Generation Sql instance to use private IPs instead of public IPs.",
    @@ -1252,7 +1252,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from public IP addresses.",
    @@ -1273,7 +1273,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to enforce all incoming connections to SQL database instance to use SSL.",
    @@ -1292,8 +1292,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "It is recommended to set a password for the administrative user (`root` by default) to prevent unauthorized access to the SQL database instances.  This recommendation is applicable only for MySQL Instances. PostgreSQL does not offer any setting for No Password from the cloud console.",
    @@ -1314,8 +1314,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `skip_show_database` database flag for Cloud SQL Mysql instance to `on`",
    @@ -1336,8 +1336,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set the `local_infile` database flag for a Cloud SQL MySQL instance to `off`.",
    @@ -1358,8 +1358,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The `log_error_verbosity` flag controls the verbosity/details of messages logged. Valid values are: - `TERSE` - `DEFAULT` - `VERBOSE`  `TERSE` excludes the logging of `DETAIL`, `HINT`, `QUERY`, and `CONTEXT` error information.  `VERBOSE` output includes the `SQLSTATE` error code, source code file name, function name, and line number that generated the error.  Ensure an appropriate value is set to 'DEFAULT' or stricter.",
    @@ -1380,8 +1380,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_error_statement` flag defines the minimum message severity level that are considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. Ensure a value of `ERROR` or stricter is set.",
    @@ -1402,8 +1402,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The value of `log_statement` flag determined the SQL statements that are logged. Valid values are: - `none` - `ddl` - `mod` - `all`  The value `ddl` logs all data definition statements. The value `mod` logs all ddl statements, plus data-modifying statements.  The statements are logged after a basic parsing is done and statement type is determined, thus this does not logs statements with errors. When using extended query protocol, logging occurs after an Execute message is received and values of the Bind parameters are included.  A value of 'ddl' is recommended unless otherwise directed by your organization's logging policy.",
    @@ -1424,8 +1424,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Instance addresses can be public IP or private IP. Public IP means that the instance is accessible through the public internet. In contrast, instances using only private IP are not accessible through the public internet, but are accessible through a Virtual Private Cloud (VPC).  Limiting network access to your database will limit potential attacks.",
    @@ -1446,8 +1446,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure `cloudsql.enable_pgaudit` database flag for Cloud SQL PostgreSQL instance is set to `on` to allow for centralized logging.",
    @@ -1468,8 +1468,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling the `log_connections` setting causes each attempted connection to the server to be logged, along with successful completion of client authentication. This parameter cannot be changed after the session starts.",
    @@ -1490,8 +1490,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling the `log_disconnections` setting logs the end of each session, including the session duration.",
    @@ -1512,8 +1512,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_duration_statement` flag defines the minimum amount of execution time of a statement in milliseconds where the total duration of the statement is logged. Ensure that `log_min_duration_statement` is disabled, i.e., a value of `-1` is set.",
    @@ -1534,8 +1534,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_messages` flag defines the minimum message severity level that is considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. ERROR is considered the best practice setting. Changes should only be made in accordance with the organization's logging policy.",
    @@ -1556,8 +1556,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `3625 (trace flag)` database flag for Cloud SQL SQL Server instance to `on`.",
    @@ -1578,8 +1578,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `external scripts enabled` database flag for Cloud SQL SQL Server instance to `off`",
    @@ -1600,8 +1600,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `remote access` database flag for Cloud SQL SQL Server instance to `off`.",
    @@ -1622,8 +1622,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to check the `user connections` for a Cloud SQL SQL Server instance to ensure that it is not artificially limiting connections.",
    @@ -1644,8 +1644,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that, `user options` database flag for Cloud SQL SQL Server instance should not be configured.",
    @@ -1666,8 +1666,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `contained database authentication` database flag for Cloud SQL on the SQL Server instance to `off`.",
    @@ -1688,8 +1688,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `cross db ownership chaining` database flag for Cloud SQL SQL Server instance to `off`.",
    @@ -1710,7 +1710,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets.",
    @@ -1731,7 +1731,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets. If CMEK is used, the CMEK is used to encrypt the data encryption keys instead of using google-managed encryption keys.",
    @@ -1752,7 +1752,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the IAM policy on BigQuery datasets does not allow anonymous and/or public access.",
    diff --git a/prowler/compliance/gcp/cis_3.0_gcp.json b/prowler/compliance/gcp/cis_3.0_gcp.json
    index a0e860e81d..8ebe8cd6df 100644
    --- a/prowler/compliance/gcp/cis_3.0_gcp.json
    +++ b/prowler/compliance/gcp/cis_3.0_gcp.json
    @@ -10,7 +10,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Use corporate login credentials instead of consumer accounts, such as Gmail accounts.",
    @@ -30,7 +30,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Setup multi-factor authentication for Google Cloud Platform accounts.",
    @@ -50,7 +50,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Setup Security Key Enforcement for Google Cloud Platform admin accounts.",
    @@ -72,7 +72,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "User-managed service accounts should not have user-managed keys.",
    @@ -94,7 +94,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "A service account is a special Google account that belongs to an application or a VM, instead of to an individual end-user. The application uses the service account to call the service's Google API so that users aren't directly involved. It's recommended not to use admin access for ServiceAccount.",
    @@ -116,7 +116,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to assign the `Service Account User (iam.serviceAccountUser)` and `Service Account Token Creator (iam.serviceAccountTokenCreator)` roles to a user for a specific service account rather than assigning the role to a user at project level.",
    @@ -138,7 +138,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Service Account keys consist of a key ID (Private_key_Id) and Private key, which are used to sign programmatic requests users make to Google cloud services accessible to that particular service account. It is recommended that all Service Account keys are regularly rotated.",
    @@ -160,7 +160,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning service-account related roles to users.",
    @@ -182,7 +182,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the IAM policy on Cloud KMS `cryptokeys` should restrict anonymous and/or public access.",
    @@ -204,7 +204,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud Key Management Service stores cryptographic keys in a hierarchical structure designed for useful and elegant access control management. The format for the rotation schedule depends on the client library that is used. For the gcloud command-line tool, the next rotation time must be in `ISO` or `RFC3339` format, and the rotation period must be in the form `INTEGER[UNIT]`, where units can be one of seconds (s), minutes (m), hours (h) or days (d).",
    @@ -226,7 +226,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning KMS related roles to users.",
    @@ -248,7 +248,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. Unused keys with their permissions in tact may still exist within a project. Keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to use standard authentication flow instead.",
    @@ -268,7 +268,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. In this case, unrestricted keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API key usage to trusted hosts, HTTP referrers and apps. It is recommended to use the more secure standard authentication flow instead.",
    @@ -290,7 +290,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. API keys are always at risk because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API keys to use (call) only APIs required by an application.",
    @@ -312,7 +312,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. If they are in use it is recommended to rotate API keys every 90 days.",
    @@ -334,7 +334,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that Essential Contacts is configured to designate email addresses for Google Cloud services to notify of important technical or security information.",
    @@ -354,7 +354,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Identity and Access Management",
    +          "Section": "1 Identity and Access Management",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Google Cloud Functions allow you to host serverless code that is executed when an event is triggered, without the requiring the management a host operating system. These functions can also store environment variables to be used by the code that may contain authentication or other information that needs to remain confidential.",
    @@ -376,7 +376,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that Cloud Audit Logging is configured to track all admin activities and read, write access to user data.",
    @@ -398,7 +398,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to create a sink that will export copies of all the log entries. This can help aggregate logs from multiple projects and export them to a Security Information and Event Management (SIEM).",
    @@ -420,7 +420,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling retention policies on log buckets will protect logs stored in cloud storage buckets from being overwritten or accidentally deleted. It is recommended to set up retention policies and configure Bucket Lock on all storage buckets that are used as log sinks.",
    @@ -442,7 +442,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In order to prevent unnecessary project ownership assignments to users/service-accounts and further misuses of projects and resources, all `roles/Owner` assignments should be monitored.Members (users/Service-Accounts) with a role assignment to primitive role `roles/Owner` are project owners.The project owner has all the privileges on the project the role belongs to. These are summarized below:- All viewer permissions on all GCP Services within the project- Permissions for actions that modify the state of all GCP services within the project- Manage roles and permissions for a project and all resources within the project- Set up billing for a projectGranting the owner role to a member (user/Service-Account) will allow that member to modify the Identity and Access Management (IAM) policy. Therefore, grant the owner role only if the member has a legitimate purpose to manage the IAM policy. This is because the project IAM policy contains sensitive access control data. Having a minimal set of users allowed to manage IAM policy will simplify any auditing that may be necessary.",
    @@ -464,7 +464,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud Platform (GCP) services write audit log entries to the Admin Activity and Data Access logs to help answer the questions of, \"who did what, where, and when?\" within GCP projects.Cloud audit logging records information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by GCP services. Cloud audit logging provides a history of GCP API calls for an account, including API calls made via the console, SDKs, command-line tools, and other GCP services.",
    @@ -486,7 +486,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for changes to Identity and Access Management (IAM) role creation, deletion and updating activities.",
    @@ -508,7 +508,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) Network Firewall rule changes.",
    @@ -530,7 +530,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network route changes.",
    @@ -552,7 +552,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network changes.",
    @@ -574,7 +574,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for Cloud Storage Bucket IAM changes.",
    @@ -596,7 +596,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that a metric filter and alarm be established for SQL instance configuration changes.",
    @@ -616,7 +616,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cloud DNS logging records the queries from the name servers within your VPC to Stackdriver. Logged queries can come from Compute Engine VMs, GKE containers, or other GCP resources provisioned within the VPC.",
    @@ -638,7 +638,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.Cloud Asset Inventory Service (CAIS) API enablement is not required for operation of the service, but rather enables the mechanism for searching/exporting CAIS asset data directly.",
    @@ -658,7 +658,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "GCP Access Transparency provides audit logs for all actions that Google personnel take in your Google Cloud resources.",
    @@ -680,7 +680,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP Access Approval enables you to require your organizations' explicit approval whenever Google support try to access your projects. You can then select users within your organization who can approve these requests through giving them a security role in IAM. All access requests display which Google Employee requested them in an email or Pub/Sub message that you can choose to Approve. This adds an additional control and logging of who in your organization approved/denied these requests.",
    @@ -702,7 +702,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. Logging and Monitoring",
    +          "Section": "2 Logging and Monitoring",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Logging enabled on a HTTPS Load Balancer will show all network traffic and its destination.",
    @@ -724,7 +724,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "To prevent use of `default` network, a project should not have a `default` network.",
    @@ -746,7 +746,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In order to prevent use of legacy networks, a project should not have a legacy network configured. As of now, Legacy Networks are gradually being phased out, and you can no longer create projects with them. This recommendation is to check older projects to ensure that they are not using Legacy Networks.",
    @@ -768,7 +768,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Cloud Domain Name System (DNS) is a fast, reliable and cost-effective domain name system that powers millions of domains on the internet. Domain Name System Security Extensions (DNSSEC) in Cloud DNS enables domain owners to take easy steps to protect their domains against DNS hijacking and man-in-the-middle and other attacks.",
    @@ -790,7 +790,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
    @@ -812,7 +812,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
    @@ -834,7 +834,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow the user to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, only an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the internet to VPC or VM instance using `SSH` on `Port 22` can be avoided.",
    @@ -856,7 +856,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow users to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the Internet to a VPC or VM instance using `RDP` on `Port 3389` can be avoided.",
    @@ -878,7 +878,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Flow Logs is a feature that enables users to capture information about the IP traffic going to and from network interfaces in the organization's VPC Subnets. Once a flow log is created, the user can view and retrieve its data in Stackdriver Logging. It is recommended that Flow Logs be enabled for every business-critical VPC subnet.",
    @@ -898,7 +898,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Secure Sockets Layer (SSL) policies determine what port Transport Layer Security (TLS) features clients are permitted to use when connecting to load balancers. To prevent usage of insecure features, SSL policies should use (a) at least TLS 1.2 with the MODERN profile; or (b) the RESTRICTED profile, because it effectively requires clients to use TLS 1.2 regardless of the chosen minimum TLS version; or (3) a CUSTOM profile that does not support any of the following features: ```TLS_RSA_WITH_AES_128_GCM_SHA256TLS_RSA_WITH_AES_256_GCM_SHA384TLS_RSA_WITH_AES_128_CBC_SHATLS_RSA_WITH_AES_256_CBC_SHATLS_RSA_WITH_3DES_EDE_CBC_SHA```",
    @@ -918,7 +918,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Networking",
    +          "Section": "3 Networking",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "IAP authenticates the user requests to your apps via a Google single sign in. You can then manage these users with permissions to control access. It is recommended to use both IAP permissions and firewalls to restrict this access to your apps with sensitive information.",
    @@ -940,7 +940,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to configure your instance to not use the default Compute Engine service account because it has the Editor role on the project.",
    @@ -962,7 +962,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account `Compute Engine default service account` with Scope `Allow full access to all Cloud APIs`.",
    @@ -984,7 +984,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to use Instance specific SSH key(s) instead of using common/shared project-wide SSH key(s) to access Instances.",
    @@ -1006,7 +1006,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling OS login binds SSH certificates to IAM users and facilitates effective SSH certificate management.",
    @@ -1028,7 +1028,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Interacting with a serial port is often referred to as the serial console, which is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support.If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. Therefore interactive serial console support should be disabled.",
    @@ -1050,7 +1050,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets.Forwarding of data packets should be disabled to prevent data loss or information disclosure.",
    @@ -1072,7 +1072,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Customer-Supplied Encryption Keys (CSEK) are a feature in Google Cloud Storage and Google Compute Engine. If you supply your own encryption keys, Google uses your key to protect the Google-generated keys used to encrypt and decrypt your data. By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.",
    @@ -1094,7 +1094,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "To defend against advanced threats and ensure that the boot loader and firmware on your VMs are signed and untampered, it is recommended that Compute instances are launched with Shielded VM enabled.",
    @@ -1116,7 +1116,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Compute instances should not be configured to have external IP addresses.",
    @@ -1136,7 +1136,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "In order to maintain the highest level of security all connections to an application should be secure by default.",
    @@ -1158,7 +1158,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Google Cloud encrypts data at-rest and in-transit, but customer data must be decrypted for processing. Confidential Computing is a breakthrough technology which encrypts data in-use—while it is being processed. Confidential Computing environments keep data encrypted in memory and elsewhere outside the central processing unit (CPU). Confidential VMs leverage the Secure Encrypted Virtualization (SEV) feature of AMD EPYC™ CPUs. Customer data will stay encrypted while it is used, indexed, queried, or trained on. Encryption keys are generated in hardware, per VM, and not exportable. Thanks to built-in hardware optimizations of both performance and security, there is no significant performance penalty to Confidential Computing workloads.",
    @@ -1178,7 +1178,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Virtual Machines",
    +          "Section": "4 Virtual Machines",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Google Cloud Virtual Machines have the ability via an OS Config agent API to periodically (about every 10 minutes) report OS inventory data. A patch compliance API periodically reads this data, and cross references metadata to determine if the latest updates are installed.This is not the only Patch Management solution available to your organization and you should weigh your needs before committing to using this method.",
    @@ -1200,7 +1200,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Storage",
    +          "Section": "5 Storage",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that IAM policy on Cloud Storage bucket does not allows anonymous or public access.",
    @@ -1222,7 +1222,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Storage",
    +          "Section": "5 Storage",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that uniform bucket-level access is enabled on Cloud Storage buckets.",
    @@ -1244,7 +1244,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to enforce all incoming connections to SQL database instance to use SSL.",
    @@ -1266,7 +1266,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from public IP addresses.",
    @@ -1288,7 +1288,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to configure Second Generation Sql instance to use private IPs instead of public IPs.",
    @@ -1310,7 +1310,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    +          "Section": "6 Cloud SQL Database Services",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to have all SQL database instances set to enable automated backups.",
    @@ -1330,8 +1330,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Manual",
               "Description": "It is recommended to set a password for the administrative user (`root` by default) to prevent unauthorized access to the SQL database instances.This recommendation is applicable only for MySQL Instances. PostgreSQL does not offer any setting for No Password from the cloud console.",
    @@ -1353,8 +1353,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `skip_show_database` database flag for Cloud SQL Mysql instance to `on`",
    @@ -1376,8 +1376,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.1. MySQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.1 MySQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set the `local_infile` database flag for a Cloud SQL MySQL instance to `off`.",
    @@ -1399,8 +1399,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The `log_error_verbosity` flag controls the verbosity/details of messages logged. Valid values are:- `TERSE`- `DEFAULT`- `VERBOSE``TERSE` excludes the logging of `DETAIL`, `HINT`, `QUERY`, and `CONTEXT` error information.`VERBOSE` output includes the `SQLSTATE` error code, source code file name, function name, and line number that generated the error.Ensure an appropriate value is set to 'DEFAULT' or stricter.",
    @@ -1422,8 +1422,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling the `log_connections` setting causes each attempted connection to the server to be logged, along with successful completion of client authentication. This parameter cannot be changed after the session starts.",
    @@ -1445,8 +1445,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Enabling the `log_disconnections` setting logs the end of each session, including the session duration.",
    @@ -1468,8 +1468,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The value of `log_statement` flag determined the SQL statements that are logged. Valid values are:- `none`- `ddl`- `mod`- `all`The value `ddl` logs all data definition statements.The value `mod` logs all ddl statements, plus data-modifying statements.The statements are logged after a basic parsing is done and statement type is determined, thus this does not logs statements with errors. When using extended query protocol, logging occurs after an Execute message is received and values of the Bind parameters are included.A value of 'ddl' is recommended unless otherwise directed by your organization's logging policy.",
    @@ -1491,8 +1491,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_messages` flag defines the minimum message severity level that is considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include (from lowest to highest severity) `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`.Each severity level includes the subsequent levels mentioned above. ERROR is considered the best practice setting. Changes should only be made in accordance with the organization's logging policy.",
    @@ -1514,8 +1514,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_error_statement` flag defines the minimum message severity level that are considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include (from lowest to highest severity) `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`.Each severity level includes the subsequent levels mentioned above. Ensure a value of `ERROR` or stricter is set.",
    @@ -1537,8 +1537,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The `log_min_duration_statement` flag defines the minimum amount of execution time of a statement in milliseconds where the total duration of the statement is logged. Ensure that `log_min_duration_statement` is disabled, i.e., a value of `-1` is set.",
    @@ -1560,8 +1560,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.2. PostgreSQL Database",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.2 PostgreSQL Database",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Ensure `cloudsql.enable_pgaudit` database flag for Cloud SQL PostgreSQL instance is set to `on` to allow for centralized logging.",
    @@ -1583,8 +1583,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `external scripts enabled` database flag for Cloud SQL SQL Server instance to `off`",
    @@ -1606,8 +1606,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `cross db ownership chaining` database flag for Cloud SQL SQL Server instance to `off`.This flag is deprecated for all SQL Server versions in CGP. Going forward, you can't set its value to on. However, if you have this flag enabled, we strongly recommend that you either remove the flag from your database or set it to off. For cross-database access, use the [Microsoft tutorial for signing stored procedures with a certificate](https://learn.microsoft.com/en-us/sql/relational-databases/tutorial-signing-stored-procedures-with-a-certificate?view=sql-server-ver16).",
    @@ -1629,8 +1629,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to check the `user connections` for a Cloud SQL SQL Server instance to ensure that it is not artificially limiting connections.",
    @@ -1652,8 +1652,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that, `user options` database flag for Cloud SQL SQL Server instance should not be configured.",
    @@ -1675,8 +1675,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `remote access` database flag for Cloud SQL SQL Server instance to `off`.",
    @@ -1694,12 +1694,12 @@
           "Id": "6.3.6",
           "Description": "Ensure '3625 (trace flag)' database flag for all Cloud SQL Server instances is set to 'on'",
           "Checks": [
    -        "cloudsql_instance_sqlserver_trace_flag\""
    +        "cloudsql_instance_sqlserver_trace_flag"
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended to set `3625 (trace flag)` database flag for Cloud SQL SQL Server instance to `on`.",
    @@ -1721,8 +1721,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6. Cloud SQL Database Services",
    -          "SubSection": "6.3. SQL Server",
    +          "Section": "6 Cloud SQL Database Services",
    +          "SubSection": "6.3 SQL Server",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended not to set `contained database authentication` database flag for Cloud SQL on the SQL Server instance to `on`.",
    @@ -1744,7 +1744,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 1",
               "AssessmentStatus": "Automated",
               "Description": "It is recommended that the IAM policy on BigQuery datasets does not allow anonymous and/or public access.",
    @@ -1766,7 +1766,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets. If CMEK is used, the CMEK is used to encrypt the data encryption keys instead of using google-managed encryption keys.",
    @@ -1788,7 +1788,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets.",
    @@ -1808,7 +1808,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7. BigQuery",
    +          "Section": "7 BigQuery",
               "Profile": "Level 2",
               "AssessmentStatus": "Manual",
               "Description": "BigQuery tables can contain sensitive data that for security purposes should be discovered, monitored, classified, and protected. Google Cloud's Sensitive Data Protection tools can automatically provide data classification of all BigQuery data across an organization.",
    @@ -1830,7 +1830,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "8. Dataproc",
    +          "Section": "8 Dataproc",
               "Profile": "Level 2",
               "AssessmentStatus": "Automated",
               "Description": "When you use Dataproc, cluster and job data is stored on Persistent Disks (PDs) associated with the Compute Engine VMs in your cluster and in a Cloud Storage staging bucket. This PD and bucket data is encrypted using a Google-generated data encryption key (DEK) and key encryption key (KEK). The CMEK feature allows you to create, use, and revoke the key encryption key (KEK). Google still controls the data encryption key (DEK).",
    diff --git a/prowler/compliance/kubernetes/cis_1.10_kubernetes.json b/prowler/compliance/kubernetes/cis_1.10_kubernetes.json
    index 7c7c9e6898..379504a127 100644
    --- a/prowler/compliance/kubernetes/cis_1.10_kubernetes.json
    +++ b/prowler/compliance/kubernetes/cis_1.10_kubernetes.json
    @@ -10,8 +10,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the API server pod specification file has permissions of `600` or more restrictive.",
    @@ -31,8 +31,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the API server pod specification file ownership is set to `root:root`.",
    @@ -52,8 +52,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.",
    @@ -73,8 +73,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the controller manager pod specification file ownership is set to `root:root`.",
    @@ -94,8 +94,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the scheduler pod specification file has permissions of `600` or more restrictive.",
    @@ -115,8 +115,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the scheduler pod specification file ownership is set to `root:root`.",
    @@ -136,8 +136,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `600` or more restrictive.",
    @@ -157,8 +157,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`.",
    @@ -178,8 +178,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the Container Network Interface files have permissions of `600` or more restrictive.",
    @@ -199,8 +199,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the Container Network Interface files have ownership set to `root:root`.",
    @@ -220,8 +220,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the etcd data directory has permissions of `700` or more restrictive.",
    @@ -241,8 +241,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the etcd data directory ownership is set to `etcd:etcd`.",
    @@ -262,8 +262,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `admin.conf` file (and `super-admin.conf` file, where it exists) have permissions of `600`.",
    @@ -283,8 +283,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `admin.conf` (and `super-admin.conf` file, where it exists) file ownership is set to `root:root`.",
    @@ -304,8 +304,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `scheduler.conf` file has permissions of `600` or more restrictive.",
    @@ -325,8 +325,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `scheduler.conf` file ownership is set to `root:root`.",
    @@ -346,8 +346,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `controller-manager.conf` file has permissions of 600 or more restrictive.",
    @@ -367,8 +367,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `controller-manager.conf` file ownership is set to `root:root`.",
    @@ -388,8 +388,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the Kubernetes PKI directory and file ownership is set to `root:root`.",
    @@ -409,8 +409,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that Kubernetes PKI certificate files have permissions of `600` or more restrictive.",
    @@ -430,8 +430,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.1. Control Plane Node Configuration Files",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that Kubernetes PKI key files have permissions of `600`.",
    @@ -453,8 +453,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Disable anonymous requests to the API server.",
    @@ -476,8 +476,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not use token based authentication.",
    @@ -499,8 +499,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "This admission controller rejects all net-new usage of the Service field externalIPs.",
    @@ -522,8 +522,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable certificate based kubelet authentication.",
    @@ -545,8 +545,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Verify kubelet's certificate before establishing connection.",
    @@ -568,8 +568,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not always authorize all requests.",
    @@ -591,8 +591,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Restrict kubelet nodes to reading only objects associated with them.",
    @@ -614,8 +614,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Turn on Role Based Access Control.",
    @@ -637,8 +637,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Limit the rate at which the API server accepts requests.",
    @@ -660,8 +660,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not allow all requests.",
    @@ -683,8 +683,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Always pull images.",
    @@ -706,8 +706,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Automate service accounts management.",
    @@ -729,8 +729,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Reject creating objects in a namespace that is undergoing termination.",
    @@ -752,8 +752,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Limit the `Node` and `Pod` objects that a kubelet could modify.",
    @@ -775,8 +775,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Disable profiling, if not needed.",
    @@ -798,8 +798,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable auditing on the Kubernetes API Server and set the desired audit log path.",
    @@ -821,8 +821,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Retain the logs for at least 30 days or as appropriate.",
    @@ -844,8 +844,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Retain 10 or an appropriate number of old log files.",
    @@ -867,8 +867,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Rotate log files on reaching 100 MB or as appropriate.",
    @@ -890,8 +890,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Set global request timeout for API server requests as appropriate.",
    @@ -913,8 +913,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Validate service account before validating token.",
    @@ -936,8 +936,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Explicitly set a service account public key file for service accounts on the apiserver.",
    @@ -959,8 +959,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "etcd should be configured to make use of TLS encryption for client connections.",
    @@ -982,8 +982,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Setup TLS connection on the API server.",
    @@ -1005,8 +1005,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Setup TLS connection on the API server.",
    @@ -1028,8 +1028,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "etcd should be configured to make use of TLS encryption for client connections.",
    @@ -1051,8 +1051,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Encrypt etcd key-value store.",
    @@ -1072,8 +1072,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Where `etcd` encryption is used, appropriate providers should be configured.",
    @@ -1095,8 +1095,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.2. API Server",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the API server is configured to only use strong cryptographic ciphers.",
    @@ -1118,8 +1118,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Activate garbage collector on pod termination, as appropriate.",
    @@ -1141,8 +1141,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Disable profiling, if not needed.",
    @@ -1164,8 +1164,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Use individual service account credentials for each controller.",
    @@ -1187,8 +1187,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Explicitly set a service account private key file for service accounts on the controller manager.",
    @@ -1210,8 +1210,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Allow pods to verify the API server's serving certificate before establishing connections.",
    @@ -1233,8 +1233,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable kubelet server certificate rotation on controller-manager.",
    @@ -1256,8 +1256,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.3. Controller Manager",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not bind the Controller Manager service to non-loopback insecure addresses.",
    @@ -1279,8 +1279,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.4. Scheduler",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.4 Scheduler",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Disable profiling, if not needed.",
    @@ -1302,8 +1302,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    -          "SubSection": "1.4. Scheduler",
    +          "Section": "1 Control Plane Components",
    +          "SubSection": "1.4 Scheduler",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not bind the scheduler service to non-loopback insecure addresses.",
    @@ -1325,7 +1325,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Configure TLS encryption for the etcd service.",
    @@ -1347,7 +1347,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable client authentication on etcd service.",
    @@ -1369,7 +1369,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not use self-signed certificates for TLS.",
    @@ -1391,7 +1391,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "etcd should be configured to make use of TLS encryption for peer connections.",
    @@ -1413,7 +1413,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "etcd should be configured for peer authentication.",
    @@ -1435,7 +1435,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not use automatically generated self-signed certificates for TLS connections between peers.",
    @@ -1457,7 +1457,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "2. etcd",
    +          "Section": "2 etcd",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Use a different certificate authority for etcd from the one used for Kubernetes.",
    @@ -1477,8 +1477,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    -          "SubSection": "3.1. Authentication and Authorization",
    +          "Section": "3 Control Plane Configuration",
    +          "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes provides the option to use client certificates for user authentication. However as there is no way to revoke these certificates when a user leaves an organization or loses their credential, they are not suitable for this purpose.It is not possible to fully disable client certificate use within a cluster as it is used for component to component authentication.",
    @@ -1498,8 +1498,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    -          "SubSection": "3.1. Authentication and Authorization",
    +          "Section": "3 Control Plane Configuration",
    +          "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes provides service account tokens which are intended for use by workloads running in the Kubernetes cluster, for authentication to the API server.These tokens are not designed for use by end-users and do not provide for features such as revocation or expiry, making them insecure. A newer version of the feature (Bound service account token volumes) does introduce expiry but still does not allow for specific revocation.",
    @@ -1519,8 +1519,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    -          "SubSection": "3.1. Authentication and Authorization",
    +          "Section": "3 Control Plane Configuration",
    +          "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes provides bootstrap tokens which are intended for use by new nodes joining the clusterThese tokens are not designed for use by end-users they are specifically designed for the purpose of bootstrapping new nodes and not for general authentication",
    @@ -1540,8 +1540,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    -          "SubSection": "3.2. Logging",
    +          "Section": "3 Control Plane Configuration",
    +          "SubSection": "3.2 Logging",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes can audit the details of requests made to the API server. The `--audit-policy-file` flag must be set for this logging to be enabled.",
    @@ -1561,8 +1561,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    -          "SubSection": "3.2. Logging",
    +          "Section": "3 Control Plane Configuration",
    +          "SubSection": "3.2 Logging",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the audit policy created for the cluster covers key security concerns.",
    @@ -1584,8 +1584,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `kubelet` service file has permissions of `600` or more restrictive.",
    @@ -1607,8 +1607,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `kubelet` service file ownership is set to `root:root`.",
    @@ -1628,8 +1628,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "If `kube-proxy` is running, and if it is using a file-based kubeconfig file, ensure that the proxy kubeconfig file has permissions of `600` or more restrictive.",
    @@ -1649,8 +1649,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "If `kube-proxy` is running, ensure that the file ownership of its kubeconfig file is set to `root:root`.",
    @@ -1672,8 +1672,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `kubelet.conf` file has permissions of `600` or more restrictive.",
    @@ -1695,8 +1695,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that the `kubelet.conf` file ownership is set to `root:root`.",
    @@ -1716,8 +1716,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the certificate authorities file has permissions of `600` or more restrictive.",
    @@ -1737,8 +1737,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the certificate authorities file ownership is set to `root:root`.",
    @@ -1760,8 +1760,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that if the kubelet refers to a configuration file with the `--config` argument, that file has permissions of 600 or more restrictive.",
    @@ -1783,8 +1783,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.1. Worker Node Configuration Files",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Ensure that if the kubelet refers to a configuration file with the `--config` argument, that file is owned by root:root.",
    @@ -1806,8 +1806,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Disable anonymous requests to the Kubelet server.",
    @@ -1829,8 +1829,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Do not allow all requests. Enable explicit authorization.",
    @@ -1852,8 +1852,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable Kubelet authentication using certificates.",
    @@ -1875,8 +1875,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Disable the read-only port.",
    @@ -1898,8 +1898,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not disable timeouts on streaming connections.",
    @@ -1921,8 +1921,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Allow Kubelet to manage iptables.",
    @@ -1942,8 +1942,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not override node hostnames.",
    @@ -1965,8 +1965,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 2 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Security relevant information should be captured. The eventRecordQPS on the Kubelet configuration can be used to limit the rate at which events are gathered and sets the maximum event creations per second. Setting this too low could result in relevant events not being logged, however the unlimited setting of `0` could result in a denial of service on the kubelet.",
    @@ -1988,8 +1988,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Setup TLS connection on the Kubelets.",
    @@ -2011,8 +2011,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Enable kubelet client certificate rotation.",
    @@ -2032,8 +2032,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Enable kubelet server certificate rotation.",
    @@ -2055,8 +2055,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the Kubelet is configured to only use strong cryptographic ciphers.",
    @@ -2076,8 +2076,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.2. Kubelet",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Ensure that the Kubelet sets limits on the number of PIDs that can be created by pods running on the node.",
    @@ -2097,8 +2097,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    -          "SubSection": "4.3. kube-proxy",
    +          "Section": "4 Worker Nodes",
    +          "SubSection": "4.3 kube-proxy",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not bind the kube-proxy metrics port to non-loopback addresses.",
    @@ -2120,8 +2120,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "The RBAC role `cluster-admin` provides wide-ranging powers over the environment and should be used only where and when needed.",
    @@ -2143,8 +2143,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "The Kubernetes API stores secrets, which may be service account tokens for the Kubernetes API or credentials used by workloads in the cluster. Access to these secrets should be restricted to the smallest possible group of users to reduce the risk of privilege escalation.",
    @@ -2166,8 +2166,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
               "Description": "Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard \"*\" which matches all items. Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product.",
    @@ -2189,8 +2189,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "The ability to create pods in a namespace can provide a number of opportunities for privilege escalation, such as assigning privileged service accounts to these pods or mounting hostPaths with access to sensitive data (unless Pod Security Policies are implemented to restrict this access)As such, access to create new pods should be restricted to the smallest possible group of users.",
    @@ -2210,8 +2210,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "The `default` service account should not be used to ensure that rights granted to applications can be more easily audited and reviewed.",
    @@ -2231,8 +2231,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
               "Description": "Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server",
    @@ -2252,8 +2252,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "The special group `system:masters` should not be used to grant permissions to any user or service account, except where strictly necessary (e.g. bootstrapping access prior to RBAC being fully available)",
    @@ -2273,8 +2273,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Cluster roles and roles with the impersonate, bind or escalate permissions should not be granted unless strictly required. Each of these permissions allow a particular subject to escalate their privileges beyond those explicitly granted by cluster administrators",
    @@ -2296,8 +2296,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "The ability to create persistent volumes in a cluster can provide an opportunity for privilege escalation, via the creation of `hostPath` volumes. As persistent volumes are not covered by Pod Security Admission, a user with access to create persistent volumes may be able to get access to sensitive files from the underlying host even where restrictive Pod Security Admission policies are in place.",
    @@ -2319,8 +2319,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Users with access to the `Proxy` sub-resource of `Node` objects automatically have permissions to use the Kubelet API, which may allow for privilege escalation or bypass cluster security controls such as audit logs.The Kubelet provides an API which includes rights to execute commands in any container running on the node. Access to this API is covered by permissions to the main Kubernetes API via the `node` object. The proxy sub-resource specifically allows wide ranging access to the Kubelet API.Direct access to the Kubelet API bypasses controls like audit logging (there is no audit log of Kubelet API access) and admission control.",
    @@ -2342,8 +2342,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Users with access to the update the `approval` sub-resource of `certificateaigningrequests` objects can approve new client certificates for the Kubernetes API effectively allowing them to create new high-privileged user accounts.This can allow for privilege escalation to full cluster administrator, depending on users configured in the cluster",
    @@ -2365,8 +2365,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Users with rights to create/modify/delete `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` can control webhooks that can read any object admitted to the cluster, and in the case of mutating webhooks, also mutate admitted objects. This could allow for privilege escalation or disruption of the operation of the cluster.",
    @@ -2388,8 +2388,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.1. RBAC and Service Accounts",
    +          "Section": "5 Policies",
    +          "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Users with rights to create new service account tokens at a cluster level, can create long-lived privileged credentials in the cluster. This could allow for privilege escalation and persistent access to the cluster, even if the users account has been revoked.",
    @@ -2409,8 +2409,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Every Kubernetes cluster should have at least one policy control mechanism in place to enforce the other requirements in this section. This could be the in-built Pod Security Admission controller, or a third party policy control system.",
    @@ -2432,8 +2432,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run with the `securityContext.privileged` flag set to `true`.",
    @@ -2455,8 +2455,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run with the `hostPID` flag set to true.",
    @@ -2478,8 +2478,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run with the `hostIPC` flag set to true.",
    @@ -2501,8 +2501,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run with the `hostNetwork` flag set to true.",
    @@ -2524,8 +2524,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run with the `allowPrivilegeEscalation` flag set to true. Allowing this right can lead to a process running a container getting more rights than it started with.It's important to note that these rights are still constrained by the overall container sandbox, and this setting does not relate to the use of privileged containers.",
    @@ -2547,8 +2547,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers to be run as the root user.",
    @@ -2570,8 +2570,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers with the potentially dangerous NET_RAW capability.",
    @@ -2593,8 +2593,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers with capabilities assigned beyond the default set.",
    @@ -2616,8 +2616,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers with capabilities",
    @@ -2639,8 +2639,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit Windows containers to be run with the `hostProcess` flag set to true.",
    @@ -2660,8 +2660,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally admit containers which make use of `hostPath` volumes.",
    @@ -2683,8 +2683,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.2. Ensure that the cluster has at least one active policy control mechanism in place",
    +          "Section": "5 Policies",
    +          "SubSection": "5.2 Ensure that the cluster has at least one active policy control mechanism in place",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Do not generally permit containers which require the use of HostPorts.",
    @@ -2704,8 +2704,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.3. Network Policies and CNI",
    +          "Section": "5 Policies",
    +          "SubSection": "5.3 Network Policies and CNI",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "There are a variety of CNI plugins available for Kubernetes. If the CNI in use does not support Network Policies it may not be possible to effectively restrict traffic in the cluster.",
    @@ -2725,8 +2725,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.3. Network Policies and CNI",
    +          "Section": "5 Policies",
    +          "SubSection": "5.3 Network Policies and CNI",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Use network policies to isolate traffic in your cluster network.",
    @@ -2748,8 +2748,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.4. Secrets Management",
    +          "Section": "5 Policies",
    +          "SubSection": "5.4 Secrets Management",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes supports mounting secrets as data volumes or as environment variables. Minimize the use of environment variable secrets.",
    @@ -2769,8 +2769,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.4. Secrets Management",
    +          "Section": "5 Policies",
    +          "SubSection": "5.4 Secrets Management",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Consider the use of an external secrets storage and management system, instead of using Kubernetes Secrets directly, if you have more complex secret management needs. Ensure the solution requires authentication to access secrets, has auditing of access to and use of secrets, and encrypts secrets. Some solutions also make it easier to rotate secrets.",
    @@ -2790,8 +2790,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.5. Extensible Admission Control",
    +          "Section": "5 Policies",
    +          "SubSection": "5.5 Extensible Admission Control",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Configure Image Provenance for your deployment.",
    @@ -2811,8 +2811,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.7. General Policies",
    +          "Section": "5 Policies",
    +          "SubSection": "5.7 General Policies",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Use namespaces to isolate your Kubernetes objects.",
    @@ -2834,8 +2834,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.7. General Policies",
    +          "Section": "5 Policies",
    +          "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Enable `docker/default` seccomp profile in your pod definitions.",
    @@ -2855,8 +2855,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.7. General Policies",
    +          "Section": "5 Policies",
    +          "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Apply Security Context to Your Pods and Containers",
    @@ -2876,8 +2876,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    -          "SubSection": "5.7. General Policies",
    +          "Section": "5 Policies",
    +          "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
               "Description": "Kubernetes provides a default namespace, where objects are placed if no namespace is specified for them. Placing objects in this namespace makes application of RBAC and other controls more difficult.",
    diff --git a/prowler/compliance/kubernetes/cis_1.8_kubernetes.json b/prowler/compliance/kubernetes/cis_1.8_kubernetes.json
    index d5786b6668..88fcfd59b2 100644
    --- a/prowler/compliance/kubernetes/cis_1.8_kubernetes.json
    +++ b/prowler/compliance/kubernetes/cis_1.8_kubernetes.json
    @@ -10,7 +10,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -31,7 +31,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -52,7 +52,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -73,7 +73,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -94,7 +94,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -115,7 +115,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -136,7 +136,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -157,7 +157,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -178,7 +178,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -199,7 +199,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -220,7 +220,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -241,7 +241,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -262,7 +262,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -283,7 +283,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -304,7 +304,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -325,7 +325,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -346,7 +346,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -367,7 +367,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -388,7 +388,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -409,7 +409,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -430,7 +430,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.1 Control Plane Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -453,7 +453,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -476,7 +476,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -499,7 +499,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -522,7 +522,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -545,7 +545,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -568,7 +568,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -591,7 +591,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -614,7 +614,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -637,7 +637,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -660,7 +660,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -683,7 +683,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -706,7 +706,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -729,7 +729,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -752,7 +752,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -775,7 +775,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -798,7 +798,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -821,7 +821,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -844,7 +844,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -867,7 +867,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -890,7 +890,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -913,7 +913,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -936,7 +936,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -959,7 +959,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -982,7 +982,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1005,7 +1005,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1028,7 +1028,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1051,7 +1051,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1074,7 +1074,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1095,7 +1095,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1118,7 +1118,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.2 API Server",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1141,7 +1141,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1164,7 +1164,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1187,7 +1187,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1210,7 +1210,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1233,7 +1233,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1256,7 +1256,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1279,7 +1279,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.3 Controller Manager",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1302,7 +1302,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.4 Scheduler",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1325,7 +1325,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "1. Control Plane Components",
    +          "Section": "1 Control Plane Components",
               "SubSection": "1.4 Scheduler",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1500,7 +1500,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    +          "Section": "3 Control Plane Configuration",
               "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1521,7 +1521,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    +          "Section": "3 Control Plane Configuration",
               "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1542,7 +1542,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    +          "Section": "3 Control Plane Configuration",
               "SubSection": "3.1 Authentication and Authorization",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1563,7 +1563,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    +          "Section": "3 Control Plane Configuration",
               "SubSection": "3.2 Logging",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1584,7 +1584,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3. Control Plane Configuration",
    +          "Section": "3 Control Plane Configuration",
               "SubSection": "3.2 Logging",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -1607,7 +1607,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -1630,7 +1630,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1651,7 +1651,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1672,7 +1672,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1695,7 +1695,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1718,7 +1718,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1739,7 +1739,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1760,7 +1760,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1783,7 +1783,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1806,7 +1806,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.1 Worker Node Configuration Files",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1829,7 +1829,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1852,7 +1852,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1875,7 +1875,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1898,7 +1898,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1921,7 +1921,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1944,7 +1944,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -1965,7 +1965,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -1988,7 +1988,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 2 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2011,7 +2011,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2034,7 +2034,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Automated",
    @@ -2055,7 +2055,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2078,7 +2078,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2099,7 +2099,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "4. Worker Nodes",
    +          "Section": "4 Worker Nodes",
               "SubSection": "4.2 Kubelet",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2122,7 +2122,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2145,7 +2145,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2168,7 +2168,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Worker Node",
               "AssessmentStatus": "Manual",
    @@ -2191,7 +2191,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2212,7 +2212,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2233,7 +2233,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2254,7 +2254,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2275,7 +2275,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2298,7 +2298,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2321,7 +2321,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2344,7 +2344,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2367,7 +2367,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2390,7 +2390,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.1 RBAC and Service Accounts",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2411,7 +2411,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2434,7 +2434,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2457,7 +2457,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2480,7 +2480,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2503,7 +2503,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2526,7 +2526,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2549,7 +2549,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2572,7 +2572,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2595,7 +2595,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Automated",
    @@ -2618,7 +2618,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2641,7 +2641,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2662,7 +2662,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2685,7 +2685,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.2 Pod Security Standards",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2706,7 +2706,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.3 Network Policies and CNI",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2727,7 +2727,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.3 Network Policies and CNI",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2750,7 +2750,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.4 Secrets Management",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2771,7 +2771,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.4 Secrets Management",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2792,7 +2792,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.4 Secrets Management",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2813,7 +2813,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.7 General Policies",
               "Profile": "Level 1 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2836,7 +2836,7 @@
           ],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2857,7 +2857,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    @@ -2878,7 +2878,7 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5. Policies",
    +          "Section": "5 Policies",
               "SubSection": "5.7 General Policies",
               "Profile": "Level 2 - Master Node",
               "AssessmentStatus": "Manual",
    diff --git a/prowler/compliance/m365/cis_4.0_m365.json b/prowler/compliance/m365/cis_4.0_m365.json
    index 608258a387..07f2bc2d29 100644
    --- a/prowler/compliance/m365/cis_4.0_m365.json
    +++ b/prowler/compliance/m365/cis_4.0_m365.json
    @@ -12,7 +12,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1.1",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.1 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Administrative accounts are special privileged accounts that could have varying levels of access to data, users, and settings. Regular user accounts should never be utilized for administrative tasks and care should be taken, in the case of a hybrid environment, to keep Administrative accounts separated from on-prem accounts. Administrative accounts should not have applications assigned so that they have no access to potentially vulnerable services (EX. email, Teams, SharePoint, etc.) and only access to perform tasks as needed for administrative purposes.Ensure administrative accounts are not `On-premises sync enabled`.",
    @@ -32,7 +33,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.1",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.1 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Emergency access or \"break glass\" accounts are limited for emergency scenarios where normal administrative accounts are unavailable. They are not assigned to a specific user and will have a combination of physical and technical controls to prevent them from being accessed outside a true emergency. These emergencies could be due to several things, including:- Technical failures of a cellular provider or Microsoft related service such as MFA.- The last remaining Global Administrator account is inaccessible.Ensure two `Emergency Access` accounts have been defined.**Note:** Microsoft provides several recommendations for these accounts and how to configure them. For more information on this, please refer to the references section. The CIS Benchmark outlines the more critical things to consider.",
    @@ -54,7 +56,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1.1",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.1 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "More than one global administrator should be designated so a single admin can be monitored and to provide redundancy should a single admin leave an organization. Additionally, there should be no more than four global admins set for any tenant. Ideally global administrators will have no licenses assigned to them.",
    @@ -76,7 +79,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1.1",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.1 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Administrative accounts are special privileged accounts that could have varying levels of access to data, users, and settings. A license can enable an account to gain access to a variety of different applications, depending on the license assigned.The recommended state is to not license a privileged account or use `Microsoft Entra ID P1` or `Microsoft Entra ID P2` licenses.",
    @@ -98,7 +102,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1.2",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.2 Teams & groups",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft 365 Groups is the foundational membership service that drives all teamwork across Microsoft 365. With Microsoft 365 Groups, you can give a group of people access to a collection of shared resources. While there are several different group types this recommendation concerns **Microsoft 365 Groups**.In the Administration panel, when a group is created, the default privacy value is \"Public\".",
    @@ -118,7 +123,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.2",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.2 Teams & groups",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Shared mailboxes are used when multiple people need access to the same mailbox, such as a company information or support email address, reception desk, or other function that might be shared by multiple people.Users with permissions to the group mailbox can send as or send on behalf of the mailbox email address if the administrator has given that user permissions to do that. This is particularly useful for help and support mailboxes because users can send emails from \"Contoso Support\" or \"Building A Reception Desk.\"Shared mailboxes are created with a corresponding user account using a system generated password that is unknown at the time of creation.The recommended state is `Sign in blocked` for `Shared mailboxes`.",
    @@ -140,7 +146,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft cloud-only accounts have a pre-defined password policy that cannot be changed. The only items that can change are the number of days until a password expires and whether or whether passwords expire at all.",
    @@ -160,7 +167,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Idle session timeout allows the configuration of a setting which will timeout inactive users after a pre-determined amount of time. When a user reaches the set idle timeout session, they'll get a notification that they're about to be signed out. They have to select to stay signed in or they'll be automatically signed out of all Microsoft 365 web apps. Combined with a Conditional Access rule this will only impact unmanaged devices. A managed device is considered a device managed that is compliant or joined to a domain and using a supported browser like Microsoft Edge or Google Chrome (with the Microsoft Single Sign On) extension.The following Microsoft 365 web apps are supported.- Outlook Web App- OneDrive- SharePoint- Microsoft Fabric- Microsoft365.com and other start pages- Microsoft 365 web apps (Word, Excel, PowerPoint)- Microsoft 365 Admin Center- M365 Defender Portal- Microsoft Purview Compliance PortalThe recommended setting is `3 hours` (or less) for unmanaged devices. **Note:** Idle session timeout doesn't affect Microsoft 365 desktop and mobile apps.",
    @@ -180,7 +188,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "External calendar sharing allows an administrator to enable the ability for users to share calendars with anyone outside of the organization. Outside users will be sent a URL that can be used to view the calendar.",
    @@ -200,7 +209,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "By default, users can install add-ins in their Microsoft Word, Excel, and PowerPoint applications, allowing data access within the application.Do not allow users to install add-ins in Word, Excel, or PowerPoint.",
    @@ -220,7 +230,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Forms can be used for phishing attacks by asking personal or sensitive information and collecting the results. Microsoft 365 has built-in protection that will proactively scan for phishing attempt in forms such personal information request.",
    @@ -240,7 +251,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Customer Lockbox is a security feature that provides an additional layer of control and transparency to customer data in Microsoft 365. It offers an approval process for Microsoft support personnel to access organization data and creates an audited trail to meet compliance requirements.",
    @@ -260,7 +272,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Third-party storage can be enabled for users in Microsoft 365, allowing them to store and share documents using services such as Dropbox, alongside OneDrive and team sites.Ensure `Microsoft 365 on the web` third-party storage services are restricted.",
    @@ -280,7 +293,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "1.3",
    +          "Section": "1 Microsoft 365 admin center",
    +          "SubSection": "1.3 Settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Sway is a Microsoft 365 app that lets organizations create interactive, web-based presentations using images, text, videos and other media. Its design engine simplifies the process, allowing for quick customization. Presentations can then be shared via a link.This setting controls user Sway sharing capability, both within and outside of the organization. By default, Sway is enabled for everyone in the organization.",
    @@ -300,7 +314,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Enabling Safe Links policy for Office applications allows URL's that exist inside of Office documents and email applications opened by Office, Office Online and Office mobile to be processed against Defender for Office time-of-click verification and rewritten if required.**Note:** E5 Licensing includes a number of Built-in Protection policies. When auditing policies note which policy you are viewing, and keep in mind CIS recommendations often extend the Default or Build-in Policies provided by MS. In order to **Pass** the highest priority policy must match all settings recommended.",
    @@ -322,7 +337,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The Common Attachment Types Filter lets a user block known and custom malicious file types from being attached to emails.",
    @@ -344,7 +360,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Exchange Online Protection (EOP) is the cloud-based filtering service that protects organizations against spam, malware, and other email threats. EOP is included in all Microsoft 365 organizations with Exchange Online mailboxes.EOP uses flexible anti-malware policies for malware protection settings. These policies can be set to notify Admins of malicious activity.",
    @@ -364,7 +381,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Safe Attachments policy helps protect users from malware in email attachments by scanning attachments for viruses, malware, and other malicious content. When an email attachment is received by a user, Safe Attachments will scan the attachment in a secure environment and provide a verdict on whether the attachment is safe or not.",
    @@ -384,7 +402,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Safe Attachments for SharePoint, OneDrive, and Microsoft Teams scans these services for malicious files.",
    @@ -406,7 +425,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In Microsoft 365 organizations with mailboxes in Exchange Online or standalone Exchange Online Protection (EOP) organizations without Exchange Online mailboxes, email messages are automatically protected against spam (junk email) by EOP.Configure Exchange Online Spam Policies to copy emails and notify someone when a sender in the organization has been blocked for sending spam emails.",
    @@ -428,7 +448,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "By default, Office 365 includes built-in features that help protect users from phishing attacks. Set up anti-phishing polices to increase this protection, for example by refining settings to better detect and prevent impersonation and spoofing attacks. The default policy applies to all users within the organization and is a single view to fine-tune anti-phishing protection. Custom policies can be created and configured for specific users, groups or domains within the organization and will take precedence over the default policy for the scoped users.",
    @@ -448,7 +469,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "For each domain that is configured in Exchange, a corresponding Sender Policy Framework (SPF) record should be created.",
    @@ -470,7 +492,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "DKIM is one of the trio of Authentication methods (SPF, DKIM and DMARC) that help prevent attackers from sending messages that look like they come from your domain. DKIM lets an organization add a digital signature to outbound email messages in the message header. When DKIM is configured, the organization authorizes it's domain to associate, or sign, its name to an email message using cryptographic authentication. Email systems that get email from this domain can use a digital signature to help verify whether incoming email is legitimate.Use of DKIM in addition to SPF and DMARC to help prevent malicious actors using spoofing techniques from sending messages that look like they are coming from your domain.",
    @@ -490,7 +513,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "DMARC, or Domain-based Message Authentication, Reporting, and Conformance, assists recipient mail systems in determining the appropriate action to take when messages from a domain fail to meet SPF or DKIM authentication criteria.",
    @@ -512,7 +536,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "The Common Attachment Types Filter lets a user block known and custom malicious file types from being attached to emails. The policy provided by Microsoft covers 53 extensions, and an additional custom list of extensions can be defined.The list of 186 extensions provided in this recommendation is comprehensive but not exhaustive.",
    @@ -534,7 +559,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In Microsoft 365 organizations with Exchange Online mailboxes or standalone Exchange Online Protection (EOP) organizations without Exchange Online mailboxes, connection filtering and the default connection filter policy identify good or bad source email servers by IP addresses. The key components of the default connection filter policy are **IP Allow List**, **IP Block List** and **Safe list**.The recommended state is `IP Allow List` empty or undefined.",
    @@ -556,7 +582,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "In Microsoft 365 organizations with Exchange Online mailboxes or standalone Exchange Online Protection (EOP) organizations without Exchange Online mailboxes, connection filtering and the default connection filter policy identify good or bad source email servers by IP addresses. The key components of the default connection filter policy are **IP Allow List**, **IP Block List** and **Safe list**.The safe list is a pre-configured allow list that is dynamically updated by Microsoft.The recommended safe list state is: `Off` or `False`",
    @@ -578,7 +605,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "2.1",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.1 Email & collaboration",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Anti-spam protection is a feature of Exchange Online that utilizes policies to help to reduce the amount of junk email, bulk and phishing emails a mailbox receives. These policies contain lists to allow or block specific senders or domains. - The allowed senders list- The allowed domains list- The blocked senders list- The blocked domains listThe recommended state is: Do not define any `Allowed domains`",
    @@ -598,7 +626,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.4",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.4 System",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Identify _priority accounts_ to utilize Microsoft 365's advanced custom security features. This is an essential tool to bolster protection for users who are frequently targeted due to their critical positions, such as executives, leaders, managers, or others who have access to sensitive, confidential, financial, or high-priority information.Once these accounts are identified, several services and features can be enabled, including threat policies, enhanced sign-in protection through conditional access policies, and alert policies, enabling faster response times for incident response teams.",
    @@ -618,7 +647,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.4",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.4 System",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Preset security policies have been established by Microsoft, utilizing observations and experiences within datacenters to strike a balance between the exclusion of malicious content from users and limiting unwarranted disruptions. These policies can apply to all, or select users and encompass recommendations for addressing spam, malware, and phishing threats. The policy parameters are pre-determined and non-adjustable.`Strict protection` has the most aggressive protection of the 3 presets.- EOP: Anti-spam, Anti-malware and Anti-phishing- Defender: Spoof protection, Impersonation protection and Advanced phishing- Defender: Safe Links and Safe Attachments**NOTE: The preset security polices cannot target Priority account TAGS currently, groups should be used instead.**",
    @@ -638,7 +668,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.4",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.4 System",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Defender for Cloud Apps is a Cloud Access Security Broker (CASB). It provides visibility into suspicious activity in Microsoft 365, enabling investigation into potential security issues and facilitating the implementation of remediation measures if necessary.Some risk detection methods provided by Entra Identity Protection also require Microsoft Defender for Cloud Apps:- Suspicious manipulation of inbox rules- Suspicious inbox forwarding- New country detection- Impossible travel detection- Activity from anonymous IP addresses- Mass access to sensitive files",
    @@ -658,7 +689,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "2.4",
    +          "Section": "2 Microsoft 365 Defender",
    +          "SubSection": "2.4 System",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Zero-hour auto purge (ZAP) is a protection feature that retroactively detects and neutralizes malware and high confidence phishing. When ZAP for Teams protection blocks a message, the message is blocked for everyone in the chat. The initial block happens right after delivery, but ZAP occurs up to 48 hours after delivery.",
    @@ -680,7 +712,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "3.1",
    +          "Section": "3 Microsoft Purview",
    +          "SubSection": "3.1 Audit",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When audit log search is enabled in the Microsoft Purview compliance portal, user and admin activity within the organization is recorded in the audit log and retained for 90 days. However, some organizations may prefer to use a third-party security information and event management (SIEM) application to access their auditing data. In this scenario, a global admin can choose to turn off audit log search in Microsoft 365.",
    @@ -700,7 +733,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3.2",
    +          "Section": "3 Microsoft Purview",
    +          "SubSection": "3.1 Audit",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Data Loss Prevention (DLP) policies allow Exchange Online and SharePoint Online content to be scanned for specific types of data like social security numbers, credit card numbers, or passwords.",
    @@ -720,7 +754,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3.2",
    +          "Section": "3 Microsoft Purview",
    +          "SubSection": "3.1 Audit",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The default Teams Data Loss Prevention (DLP) policy rule in Microsoft 365 is a preconfigured rule that is automatically applied to all Teams conversations and channels. The default rule helps prevent accidental sharing of sensitive information by detecting and blocking certain types of content that are deemed sensitive or inappropriate by the organization. By default, the rule includes a check for the sensitive info type _Credit Card Number_ which is pre-defined by Microsoft.",
    @@ -740,7 +775,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "3.3",
    +          "Section": "3 Microsoft Purview",
    +          "SubSection": "3.3 Information protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "SharePoint Online Data Classification Policies enables organizations to classify and label content in SharePoint Online based on its sensitivity and business impact. This setting helps organizations to manage and protect sensitive data by automatically applying labels to content, which can then be used to apply policy-based protection and governance controls.",
    @@ -760,7 +796,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.1",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Security defaults in Microsoft Entra ID make it easier to be secure and help protect the organization. Security defaults contain preconfigured security settings for common attacks.By default, Microsoft enables security defaults. The goal is to ensure that all organizations have a basic level of security enabled. The security default setting is manipulated in the Entra admin center.The use of security defaults, however, will prohibit custom settings which are being set with more advanced settings from this benchmark.",
    @@ -780,7 +817,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Legacy per-user Multi-Factor Authentication (MFA) can be configured to require individual users to provide multiple authentication factors, such as passwords and additional verification codes, to access their accounts. It was introduced in earlier versions of Office 365, prior to the more comprehensive implementation of Conditional Access (CA).",
    @@ -802,7 +840,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "App registration allows users to register custom-developed applications for use within the directory.",
    @@ -824,7 +863,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Non-privileged users can create tenants in the Entra administration portal under Manage tenant. The creation of a tenant is recorded in the Audit log as category \"DirectoryManagement\" and activity \"Create Company\". Anyone who creates a tenant becomes the Global Administrator of that tenant. The newly created tenant doesn't inherit any settings or configurations.",
    @@ -844,7 +884,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Restrict non-privileged users from signing into the Microsoft Entra admin center.**Note:** This recommendation only affects access to the web portal. It does not prevent privileged users from using other methods such as Rest API or PowerShell to obtain information. Those channels are addressed elsewhere in this document.",
    @@ -864,7 +905,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "The option for the user to `Stay signed in`, or the `Keep me signed in` option, will prompt a user after a successful login. When the user selects this option, a persistent refresh token is created. The refresh token lasts for 90 days by default and does not prompt for sign-in or multifactor.",
    @@ -884,7 +926,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "LinkedIn account connections allow users to connect their Microsoft work or school account with LinkedIn. After a user connects their accounts, information and highlights from LinkedIn are available in some Microsoft apps and services.",
    @@ -906,7 +949,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "A dynamic group is a dynamic configuration of security group membership for Microsoft Entra ID. Administrators can set rules to populate groups that are created in Entra ID based on user attributes (such as userType, department, or country/region). Members can be automatically added to or removed from a security group based on their attributes.The recommended state is to create a dynamic group that includes guest accounts.",
    @@ -928,7 +972,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.5",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Control when end users and group owners are allowed to grant consent to applications, and when they will be required to request administrator review and approval. Allowing users to grant apps access to data helps them acquire useful applications and be productive but can represent a risk in some situations if it's not monitored and controlled carefully.",
    @@ -950,7 +995,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.5",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "The admin consent workflow gives admins a secure way to grant access to applications that require admin approval. When a user tries to access an application but is unable to provide consent, they can send a request for admin approval. The request is sent via email to admins who have been designated as reviewers. A reviewer takes action on the request, and the user is notified of the action.",
    @@ -970,7 +1016,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.1.6",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "B2B collaboration is a feature within Microsoft Entra External ID that allows for guest invitations to an organization.Ensure users can only send invitations to `specified domains`.**Note:** This list works independently from OneDrive for Business and SharePoint Online allow/block lists. To restrict individual file sharing in SharePoint Online, set up an allow or blocklist for OneDrive for Business and SharePoint Online. For instance, in SharePoint or OneDrive users can still share with external users from prohibited domains by using Anyone links if they haven't been disabled.",
    @@ -992,7 +1039,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.6",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft Entra ID, part of Microsoft Entra, allows you to restrict what external guest users can see in their organization in Microsoft Entra ID. Guest users are set to a limited permission level by default in Microsoft Entra ID, while the default for member users is the full set of user permissions. These directory level permissions are enforced across Microsoft Entra services including Microsoft Graph, PowerShell v2, the Azure portal, and My Apps portal. Microsoft 365 services leveraging Microsoft 365 groups for collaboration scenarios are also affected, specifically Outlook, Microsoft Teams, and SharePoint. They do not override the SharePoint or Microsoft Teams guest settings.The recommended state is at least `Guest users have limited access to properties and memberships of directory objects` or more restrictive.",
    @@ -1014,7 +1062,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.6",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "By default, all users in the organization, including B2B collaboration guest users, can invite external users to B2B collaboration. The ability to send invitations can be limited by turning it on or off for everyone, or by restricting invitations to certain roles.The recommended state for guest invite restrictions is `Only users assigned to specific admin roles can invite guest users`.",
    @@ -1036,7 +1085,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.1.8",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.1 Identity",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Password hash synchronization is one of the sign-in methods used to accomplish hybrid identity synchronization. Microsoft Entra Connect synchronizes a hash, of the hash, of a user's password from an on-premises Active Directory instance to a cloud-based Entra ID instance.**Note:** Audit and remediation procedures in this recommendation only apply to Microsoft 365 tenants operating in a hybrid configuration using Entra Connect sync, and does not apply to federated domains.",
    @@ -1058,7 +1108,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Multifactor authentication is a process that requires an additional form of identification during the sign-in process, such as a code from a mobile device or a fingerprint scan, to enhance security.Ensure users in administrator roles have MFA capabilities enabled.",
    @@ -1080,7 +1131,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Enable multifactor authentication for all users in the Microsoft 365 tenant. Users will be prompted to authenticate with a second factor upon logging in to Microsoft 365 services. The second factor is most commonly a text message to a registered mobile phone number where they type in an authorization code, or with a mobile application like Microsoft Authenticator.",
    @@ -1102,7 +1154,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Entra ID supports the most widely used authentication and authorization protocols including legacy authentication. This authentication pattern includes basic authentication, a widely used industry-standard method for collecting username and password information.The following messaging protocols support legacy authentication:- Authenticated SMTP - Used to send authenticated email messages.- Autodiscover - Used by Outlook and EAS clients to find and connect to mailboxes in Exchange Online.- Exchange ActiveSync (EAS) - Used to connect to mailboxes in Exchange Online.- Exchange Online PowerShell - Used to connect to Exchange Online with remote PowerShell. If you block Basic authentication for Exchange Online PowerShell, you need to use the Exchange Online PowerShell Module to connect. For instructions, see Connect to Exchange Online PowerShell using multifactor authentication.- Exchange Web Services (EWS) - A programming interface that's used by Outlook, Outlook for Mac, and third-party apps.- IMAP4 - Used by IMAP email clients.- MAPI over HTTP (MAPI/HTTP) - Primary mailbox access protocol used by Outlook 2010 SP2 and later.- Offline Address Book (OAB) - A copy of address list collections that are downloaded and used by Outlook.- Outlook Anywhere (RPC over HTTP) - Legacy mailbox access protocol supported by all current Outlook versions.- POP3 - Used by POP email clients.- Reporting Web Services - Used to retrieve report data in Exchange Online.- Universal Outlook - Used by the Mail and Calendar app for Windows 10.- Other clients - Other protocols identified as utilizing legacy authentication.",
    @@ -1124,7 +1177,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "In complex deployments, organizations might have a need to restrict authentication sessions. Conditional Access policies allow for the targeting of specific user accounts. Some scenarios might include:- Resource access from an unmanaged or shared device- Access to sensitive information from an external network- High-privileged users- Business-critical applicationsEnsure Sign-in frequency periodic reauthentication does not exceed `4 hours` for E3 tenants, or `24 hours` for E5 tenants using Privileged Identity Management.Ensure `Persistent browser session` is set to `Never persistent`**Note:** This CA policy can be added to the previous CA policy in this benchmark \"Ensure multifactor authentication is enabled for all users in administrative roles\"",
    @@ -1146,7 +1200,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Authentication strength is a Conditional Access control that allows administrators to specify which combination of authentication methods can be used to access a resource. For example, they can make only phishing-resistant authentication methods available to access a sensitive resource. But to access a non-sensitive resource, they can allow less secure multifactor authentication (MFA) combinations, such as password + SMS.Microsoft has 3 built-in authentication strengths. MFA strength, Passwordless MFA strength, and Phishing-resistant MFA strength. Ensure administrator roles are using a CA policy with `Phishing-resistant MFA strength`.Administrators can then enroll using one of 3 methods:- FIDO2 Security Key- Windows Hello for Business- Certificate-based authentication (Multi-Factor)**Note:** Additional steps to configure methods such as FIDO2 keys are not covered here but can be found in related MS articles in the references section. The Conditional Access policy only ensures 1 of the 3 methods is used.**Warning:** Administrators should be pre-registered for a strong authentication mechanism before this Conditional Access Policy is enforced. Additionally, as stated elsewhere in the CIS Benchmark a break-glass administrator account should be excluded from this policy to ensure unfettered access in the case of an emergency.",
    @@ -1168,7 +1223,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID Protection user risk policies detect the probability that a user account has been compromised. **Note:** While Identity Protection also provides two risk policies with limited conditions, Microsoft highly recommends setting up risk-based policies in Conditional Access as opposed to the \"legacy method\" for the following benefits:- Enhanced diagnostic data- Report-only mode integration- Graph API support- Use more Conditional Access attributes like sign-in frequency in the policy",
    @@ -1190,7 +1246,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID Protection sign-in risk detects risks in real-time and offline. A risky sign-in is an indicator for a sign-in attempt that might not have been performed by the legitimate owner of a user account.**Note:** While Identity Protection also provides two risk policies with limited conditions, Microsoft highly recommends setting up risk-based policies in Conditional Access as opposed to the \"legacy method\" for the following benefits:- Enhanced diagnostic data- Report-only mode integration- Graph API support- Use more Conditional Access attributes like sign-in frequency in the policy",
    @@ -1212,7 +1269,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "When a Conditional Access policy targets the Microsoft Admin Portals cloud app, the policy is enforced for tokens issued to application IDs of the following Microsoft administrative portals:- Azure portal- Exchange admin center- Microsoft 365 admin center- Microsoft 365 Defender portal- Microsoft Entra admin center- Microsoft Intune admin center- Microsoft Purview compliance portal- Power Platform admin center- SharePoint admin center- Microsoft Teams admin center`Microsoft Admin Portals` should be restricted to specific pre-determined administrative roles.",
    @@ -1232,7 +1290,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra ID Protection sign-in risk detects risks in real-time and offline. A risky sign-in is an indicator for a sign-in attempt that might not have been performed by the legitimate owner of a user account.**Note:** While Identity Protection also provides two risk policies with limited conditions, Microsoft highly recommends setting up risk-based policies in Conditional Access as opposed to the \"legacy method\" for the following benefits:- Enhanced diagnostic data- Report-only mode integration- Graph API support- Use more Conditional Access attributes like sign-in frequency in the policy",
    @@ -1254,7 +1313,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Conditional Access (CA) can be configured to enforce access based on the device's compliance status or whether it is Entra hybrid joined. Collectively this allows CA to classify devices as managed or unmanaged, providing more granular control over authentication policies.When using `Require device to be marked as compliant`, the device must pass checks configured in **Compliance** policies defined within Intune (Endpoint Manager). Before these checks can be applied, the device must first be enrolled in Intune MDM.By selecting `Require Microsoft Entra hybrid joined device` this means the device must first be synchronized from an on-premises Active Directory to qualify for authentication.When configured to the recommended state below only one condition needs to be met for the user to authenticate from the device. This functions as an \"OR\" operator.The recommended state is:- `Require device to be marked as compliant`- `Require Microsoft Entra hybrid joined device`- `Require one of the selected controls`",
    @@ -1276,7 +1336,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "5.2.2",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Conditional Access (CA) can be configured to enforce access based on the device's compliance status or whether it is Entra hybrid joined. Collectively this allows CA to classify devices as managed or not, providing more granular control over whether or not a user can register MFA on a device.When using `Require device to be marked as compliant`, the device must pass checks configured in **Compliance** policies defined within Intune (Endpoint Manager). Before these checks can be applied, the device must first be enrolled in Intune MDM.By selecting `Require Microsoft Entra hybrid joined device` this means the device must first be synchronized from an on-premises Active Directory to qualify for authentication.When configured to the recommended state below only one condition needs to be met for the user to register MFA from the device. This functions as an \"OR\" operator.The recommended state is to restrict `Register security information` to a device that is marked as compliant or Entra hybrid joined.",
    @@ -1296,7 +1357,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft has released additional settings to enhance the configuration of the Microsoft Authenticator application. These settings provide additional information and context to users who receive MFA passwordless and push requests, such as geographic location the request came from, the requesting application and requiring a number match.Ensure the following are `Enabled`.- `Require number matching for push notifications`- `Show application name in push and passwordless notifications`- `Show geographic location in push and passwordless notifications`**NOTE:** On February 27, 2023 Microsoft started enforcing number matching tenant-wide for all users using Microsoft Authenticator.",
    @@ -1316,7 +1378,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "With Entra Password Protection, default global banned password lists are automatically applied to all users in an Entra ID tenant. To support business and security needs, custom banned password lists can be defined. When users change or reset their passwords, these banned password lists are checked to enforce the use of strong passwords.A custom banned password list should include some of the following examples:- Brand names- Product names- Locations, such as company headquarters- Company-specific internal terms- Abbreviations that have specific company meaning",
    @@ -1336,7 +1399,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra Password Protection provides a global and custom banned password list. A password change request fails if there's a match in these banned password list. To protect on-premises Active Directory Domain Services (AD DS) environment, install and configure Entra Password Protection.**Note**: This recommendation applies to Hybrid deployments only and will have no impact unless working with on-premises Active Directory.",
    @@ -1356,7 +1420,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft defines Multifactor authentication capable as being registered and enabled for a strong authentication method. The method must also be allowed by the authentication methods policy.Ensure all member users are `MFA capable`.",
    @@ -1376,7 +1441,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Authentication methods support a wide variety of scenarios for signing in to Microsoft 365 resources. Some of these methods are inherently more secure than others but require more investment in time to get users enrolled and operational.SMS and Voice Call rely on telephony carrier communication methods to deliver the authenticating factor.The email one-time passcode feature is a way to authenticate B2B collaboration users when they can't be authenticated through other means, such as Microsoft Entra ID, Microsoft account (MSA), or social identity providers. When a B2B guest user tries to redeem your invitation or sign in to your shared resources, they can request a temporary passcode, which is sent to their email address. Then they enter this passcode to continue signing in.The recommended state is to `Disable` these methods:- SMS- Voice Call- Email OTP",
    @@ -1396,7 +1462,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.2.4",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.2 Protection",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Enabling self-service password reset allows users to reset their own passwords in Entra ID. When users sign in to Microsoft 365, they will be prompted to enter additional contact information that will help them reset their password in the future. If combined registration is enabled additional information, outside of multi-factor, will not be needed. **Note:** Effective Oct. 1st, 2022, Microsoft will begin to enable combined registration for all users in Entra ID tenants created before August 15th, 2020. Tenants created after this date are enabled with combined registration by default.",
    @@ -1416,7 +1483,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.3 Identity Governance",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra Privileged Identity Management can be used to audit roles, allow just in time activation of roles and allow for periodic role attestation. Organizations should remove permanent members from privileged Office 365 roles and instead make them eligible, through a JIT activation workflow.",
    @@ -1436,7 +1504,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.3 Identity Governance",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Access reviews enable administrators to establish an efficient automated process for reviewing group memberships, access to enterprise applications, and role assignments. These reviews can be scheduled to recur regularly, with flexible options for delegating the task of reviewing membership to different members of the organization.Ensure `Access reviews` for Guest Users are configured to be performed no less frequently than `monthly`.",
    @@ -1456,7 +1525,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.3 Identity Governance",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Access reviews enable administrators to establish an efficient automated process for reviewing group memberships, access to enterprise applications, and role assignments. These reviews can be scheduled to recur regularly, with flexible options for delegating the task of reviewing membership to different members of the organization.Ensure `Access reviews` for high privileged Entra ID roles are done `monthly` or more frequently. These reviews should include **at a minimum** the roles listed below:- Global Administrator- Exchange Administrator- SharePoint Administrator- Teams Administrator- Security Administrator**Note:** An access review is created for each role selected after completing the process.",
    @@ -1476,7 +1546,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "5.3",
    +          "Section": "5 Microsoft Entra admin center",
    +          "SubSection": "5.3 Identity Governance",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Microsoft Entra Privileged Identity Management can be used to audit roles, allow just in time activation of roles and allow for periodic role attestation. Requiring approval before activation allows one of the selected approvers to first review and then approve the activation prior to PIM granted the role. The approver doesn't have to be a group member or owner.The recommended state is `Require approval to activate` for the Global Administrator role.",
    @@ -1498,7 +1569,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.1",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.1 Audit",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The value False indicates that mailbox auditing on by default is turned on for the organization. Mailbox auditing on by default in the organization overrides the mailbox auditing settings on individual mailboxes. For example, if mailbox auditing is turned off for a mailbox (the AuditEnabled property on the mailbox is False), the default mailbox actions are still audited for the mailbox, because mailbox auditing on by default is turned on for the organization.Turning off mailbox auditing on by default ($true) has the following results:- Mailbox auditing is turned off for your organization.- From the time you turn off mailbox auditing on by default, no mailbox actions are audited, even if mailbox auditing is enabled on a mailbox (the AuditEnabled property on the mailbox is True).- Mailbox auditing isn't turned on for new mailboxes and setting the AuditEnabled property on a new or existing mailbox to True is ignored.- Any mailbox audit bypass association settings (configured by using the Set-MailboxAuditBypassAssociation cmdlet) are ignored.- Existing mailbox audit records are retained until the audit log age limit for the record expires.The recommended state for this setting is `False` at the organization level. This will enable auditing and enforce the default.",
    @@ -1520,7 +1592,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.1",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.1 Audit",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Mailbox audit logging is turned on by default in all organizations. This effort started in January 2019, and means that certain actions performed by mailbox owners, delegates, and admins are automatically logged. The corresponding mailbox audit records are available for admins to search in the mailbox audit log. Mailboxes and shared mailboxes have actions assigned to them individually in order to audit the data the organization determines valuable at the mailbox level.The recommended state is `AuditEnabled` to `True` on all user mailboxes along with additional audit actions beyond the Microsoft defaults.**Note:** Due to some differences in defaults for audit actions this recommendation is specific to users assigned an E3 license only.",
    @@ -1542,7 +1615,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.1",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.1 Audit",
               "Profile": "E5 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Mailbox audit logging is turned on by default in all organizations. This effort started in January 2019, and means that certain actions performed by mailbox owners, delegates, and admins are automatically logged. The corresponding mailbox audit records are available for admins to search in the mailbox audit log. Mailboxes and shared mailboxes have actions assigned to them individually in order to audit the data the organization determines valuable at the mailbox level.The recommended state is `AuditEnabled` to `True` on all user mailboxes along with additional audit actions beyond the Microsoft defaults.Note: Due to some differences in defaults for audit actions this recommendation is specific to users assigned an E5 license, or auditing addon license, only.",
    @@ -1564,7 +1638,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.1",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.1 Audit",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "When configuring a user or computer account to bypass mailbox audit logging, the system will not record any access, or actions performed by the said user or computer account on any mailbox. Administratively this was introduced to reduce the volume of entries in the mailbox audit logs on trusted user or computer accounts.Ensure `AuditBypassEnabled` is not enabled on accounts without a written exception.",
    @@ -1587,7 +1662,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.2",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.2 Mail Flow",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Exchange Online offers several methods of managing the flow of email messages. These are Remote domain, Transport Rules, and Anti-spam outbound policies. These methods work together to provide comprehensive coverage for potential automatic forwarding channels:- Outlook forwarding using inbox rules.- Outlook forwarding configured using OOF rule.- OWA forwarding setting (ForwardingSmtpAddress).- Forwarding set by the admin using EAC (ForwardingAddress).- Forwarding using Power Automate / Flow.Ensure a `Transport rule` and `Anti-spam outbound policy` are used to block mail forwarding.**NOTE:** Any exclusions should be implemented based on organizational policy.",
    @@ -1609,7 +1685,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.2",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.2 Mail Flow",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Mail flow rules (transport rules) in Exchange Online are used to identify and take action on messages that flow through the organization.",
    @@ -1631,7 +1708,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.2",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.2 Mail Flow",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "External callouts provide a native experience to identify emails from senders outside the organization. This is achieved by presenting a new tag on emails called \"External\" (the string is localized based on the client language setting) and exposing related user interface at the top of the message reading view to see and verify the real sender's email address.Once this feature is enabled via PowerShell, it might take 24-48 hours for users to start seeing the External sender tag in email messages received from external sources (outside of your organization), providing their Outlook version supports it.The recommended state is `ExternalInOutlook` set to `Enabled` `True`**Note:** Mail flow rules are often used by Exchange administrators to accomplish the External email tagging by appending a tag to the front of a subject line. There are limitations to this outlined [here.](https://techcommunity.microsoft.com/t5/exchange-team-blog/native-external-sender-callouts-on-email-in-outlook/ba-p/2250098) The preferred method in the CIS Benchmark is to use the native experience.",
    @@ -1653,7 +1731,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.3",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.3 Roles",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Specify the administrators and users who can install and manage add-ins for Outlook in Exchange OnlineBy default, users can install add-ins in their Microsoft Outlook Desktop client, allowing data access within the client application.",
    @@ -1675,7 +1754,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.5",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.5 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Modern authentication in Microsoft 365 enables authentication features like multifactor authentication (MFA) using smart cards, certificate-based authentication (CBA), and third-party SAML identity providers. When you enable modern authentication in Exchange Online, Outlook 2016 and Outlook 2013 use modern authentication to log in to Microsoft 365 mailboxes. When you disable modern authentication in Exchange Online, Outlook 2016 and Outlook 2013 use basic authentication to log in to Microsoft 365 mailboxes.When users initially configure certain email clients, like Outlook 2013 and Outlook 2016, they may be required to authenticate using enhanced authentication mechanisms, such as multifactor authentication. Other Outlook clients that are available in Microsoft 365 (for example, Outlook Mobile and Outlook for Mac 2016) always use modern authentication to log in to Microsoft 365 mailboxes.",
    @@ -1697,7 +1777,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.5",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.5 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "MailTips are informative messages displayed to users while they're composing a message. While a new message is open and being composed, Exchange analyzes the message (including recipients). If a potential problem is detected, the user is notified with a MailTip prior to sending the message. Using the information in the MailTip, the user can adjust the message to avoid undesirable situations or non-delivery reports (also known as NDRs or bounce messages).",
    @@ -1719,7 +1800,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.5",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.5 Settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This setting allows users to open certain external files while working in Outlook on the web. If allowed, keep in mind that ",
    @@ -1741,7 +1823,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "6.5",
    +          "Section": "6 Exchange admin center",
    +          "SubSection": "6.5 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting enables or disables authenticated client SMTP submission (SMTP AUTH) at an organization level in Exchange Online. The recommended state is `Turn off SMTP AUTH protocol for your organization` (checked).",
    @@ -1763,7 +1846,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Modern authentication in Microsoft 365 enables authentication features like multifactor authentication (MFA) using smart cards, certificate-based authentication (CBA), and third-party SAML identity providers.",
    @@ -1783,7 +1867,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Entra ID B2B provides authentication and management of guests. Authentication happens via one-time passcode when they don't already have a work or school account or a Microsoft account. Integration with SharePoint and OneDrive allows for more granular control of how guest user accounts are managed in the organization's AAD, unifying a similar guest experience already deployed in other Microsoft 365 services such as Teams.**Note:** Global Reader role currently can't access SharePoint using PowerShell.",
    @@ -1805,7 +1890,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "The external sharing settings govern sharing for the organization overall. Each site has its own sharing setting that can be set independently, though it must be at the same or more restrictive setting as the organization. The new and existing guests option requires people who have received invitations to sign in with their work or school account (if their organization uses Microsoft 365) or a Microsoft account, or to provide a code to verify their identity. Users can share with guests already in your organization's directory, and they can send invitations to people who will be added to the directory if they sign in.The recommended state is `New and existing guests` or less permissive.",
    @@ -1825,7 +1911,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This setting governs the global permissiveness of OneDrive content sharing in the organization. OneDrive content sharing can be restricted independent of SharePoint but can never be more permissive than the level established with SharePoint.The recommended state is `Only people in your organization`.",
    @@ -1847,7 +1934,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "SharePoint gives users the ability to share files, folders, and site collections. Internal users can share with external collaborators, and with the right permissions could share to other external parties.",
    @@ -1869,7 +1957,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Control sharing of documents to external domains by either blocking domains or only allowing sharing with specific named domains.",
    @@ -1889,7 +1978,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting sets the default link type that a user will see when sharing content in OneDrive or SharePoint. It does not restrict or exclude any other options.The recommended state is `Specific people (only the people the user specifies)`",
    @@ -1909,7 +1999,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "External sharing of content can be restricted to specific security groups. This setting is global, applies to sharing in both SharePoint and OneDrive and cannot be set at the site level in SharePoint.The recommended state is `Enabled` or `Checked`.**Note:** Users in these security groups must be allowed to invite guests in the guest invite settings in Microsoft Entra. Identity > External Identities > External collaboration settings",
    @@ -1929,7 +2020,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting configures the expiration time for each guest that is invited to the SharePoint site or with whom users share individual files and folders with.The recommended state is `30` or less.",
    @@ -1949,7 +2041,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting configures if guests who use a verification code to access the site or links are required to reauthenticate after a set number of days.The recommended state is `15` or less.",
    @@ -1969,7 +2062,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.2",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.2 Policies",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting configures the permission that is selected by default for sharing link from a SharePoint site.The recommended state is `View`.",
    @@ -1989,7 +2083,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.3",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.3 Settings",
               "Profile": "E5 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "By default, SharePoint online allows files that Defender for Office 365 has detected as infected to be downloaded.",
    @@ -2011,7 +2106,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "7.3",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.3 Settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft OneDrive allows users to sign in their cloud tenant account and begin syncing select folders or the entire contents of OneDrive to a local computer. By default, this includes any computer with OneDrive already installed, whether it is Entra Joined , Entra Hybrid Joined or Active Directory Domain joined.The recommended state for this setting is `Allow syncing only on computers joined to specific domains` `Enabled: Specify the AD domain GUID(s)`",
    @@ -2031,7 +2127,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.3",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This setting controls custom script execution on self-service created sites.Custom scripts can allow users to change the look, feel and behavior of sites and pages. Every script that runs in a SharePoint page (whether it's an HTML page in a document library or a JavaScript in a Script Editor Web Part) always runs in the context of the user visiting the page and the SharePoint application. This means:- Scripts have access to everything the user has access to.- Scripts can access content across several Microsoft 365 services and even beyond with Microsoft Graph integration.The recommended state is `Prevent users from running custom script on self-service created sites`.",
    @@ -2051,7 +2148,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "7.3",
    +          "Section": "7 SharePoint admin center",
    +          "SubSection": "7.3 Settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting controls custom script execution on a particular site (previously called \"site collection\").Custom scripts can allow users to change the look, feel and behavior of sites and pages. Every script that runs in a SharePoint page (whether it's an HTML page in a document library or a JavaScript in a Script Editor Web Part) always runs in the context of the user visiting the page and the SharePoint application. This means:- Scripts have access to everything the user has access to.- Scripts can access content across several Microsoft 365 services and even beyond with Microsoft Graph integration.The recommended state is `DenyAddAndCustomizePages` set to `$true`.",
    @@ -2073,7 +2171,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.1",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.1 Teams",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "Microsoft Teams enables collaboration via file sharing. This file sharing is conducted within Teams, using SharePoint Online, by default; however, third-party cloud services are allowed as well.**Note:** Skype for business is deprecated as of July 31, 2021 although these settings may still be valid for a period of time. See the link in the references section for more information.",
    @@ -2095,7 +2194,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.1",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.1 Teams",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "Teams channel email addresses are an optional feature that allows users to email the Teams channel directly.",
    @@ -2117,7 +2217,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.2",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.2 Users",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This policy controls whether external domains are allowed, blocked or permitted based on an allowlist or denylist. When external domains are allowed, users in your organization can chat, add users to meetings, and use audio video conferencing with users in external organizations.The recommended state is `Allow only specific external domains` or `Block all external domains`.",
    @@ -2139,7 +2240,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.2",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.2 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls chats and meetings with external unmanaged Teams users (those not managed by an organization, such as Microsoft Teams (free)). The recommended state is: `People in my organization can communicate with Teams users whose accounts aren't managed by an organization` set to `Off`.",
    @@ -2161,7 +2263,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.2",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.2 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This setting prevents external users who are not managed by an organization from initiating contact with users in the protected organization.The recommended state is to uncheck `External users with Teams accounts not managed by an organization can contact users in my organization`.**Note:** Disabling this setting is used as an additional stop gap for the previous setting which disables communication with unmanaged Teams users entirely. If an organization chooses to have an exception to **(L1) Ensure communication with unmanaged Teams users is disabled** they can do so while also disabling the ability for the same group of users to initiate contact. Disabling communication entirely will also disable the ability for unmanaged users to initiate contact.",
    @@ -2181,7 +2284,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8.2",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.2 Users",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls chat with external unmanaged Skype users.**Note:** Skype for business is deprecated as of July 31, 2021, although these settings may still be valid for a period of time. See the link in the reference section for more information.",
    @@ -2201,7 +2305,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "8.4",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.4 Teams apps",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This policy setting controls which class of apps are available for users to install.",
    @@ -2223,7 +2328,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting can prevent anyone other than invited attendees (people directly invited by the organizer, or to whom an invitation was forwarded) from bypassing the lobby and entering the meeting.For more information on how to setup a sensitive meeting, please visit **Configure Teams meetings with protection for sensitive data - Microsoft Teams:** https://learn.microsoft.com/en-us/MicrosoftTeams/configure-meetings-sensitive-protection",
    @@ -2245,7 +2351,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls if an anonymous participant can start a Microsoft Teams meeting without someone in attendance. Anonymous users and dial-in callers must wait in the lobby until the meeting is started by someone in the organization or an external user from a trusted organization.Anonymous participants are classified as:- Participants who are not logged in to Teams with a work or school account.- Participants from non-trusted organizations (as configured in external access).- Participants from organizations where there is not mutual trust.**Note:** This setting only applies when `Who can bypass the lobby` is set to `Everyone`. If the `anonymous users can join a meeting` organization-level setting or meeting policy is `Off`, this setting only applies to dial-in callers.",
    @@ -2267,7 +2374,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls who can join a meeting directly and who must wait in the lobby until they're admitted by an organizer, co-organizer, or presenter of the meeting.",
    @@ -2289,7 +2397,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls if users who dial in by phone can join the meeting directly or must wait in the lobby. Admittance to the meeting from the lobby is authorized by the meeting organizer, co-organizer, or presenter of the meeting.",
    @@ -2311,7 +2420,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls who has access to read and write chat messages during a meeting.",
    @@ -2333,7 +2443,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting controls who can present in a Teams meeting. **Note:** Organizers and co-organizers can change this setting when the meeting is set up.",
    @@ -2355,7 +2466,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "This policy setting allows control of who can present in meetings and who can request control of the presentation while a meeting is underway.",
    @@ -2377,7 +2489,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This meeting policy setting controls whether users can read or write messages in external meeting chats with untrusted organizations. If an external organization is on the list of trusted organizations this setting will be ignored.",
    @@ -2399,7 +2512,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.5",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.5 Meetings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Automated",
               "Description": "This setting controls the ability for a user to initiate a recording of a meeting in progress.The recommended state is `Off` for the `Global (Org-wide default)` meeting policy.",
    @@ -2422,7 +2536,8 @@
           ],
           "Attributes": [
             {
    -          "Section": "8.6",
    +          "Section": "8 Microsoft Teams admin center",
    +          "SubSection": "8.6 Messaging",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Automated",
               "Description": "User reporting settings allow a user to report a message as malicious for further analysis. This recommendation is composed of 3 different settings and all be configured to pass:- **In the Teams admin center:** On by default and controls whether users are able to report messages from Teams. When this setting is turned off, users can't report messages within Teams, so the corresponding setting in the Microsoft 365 Defender portal is irrelevant.- **In the Microsoft 365 Defender portal:** On by default for new tenants. Existing tenants need to enable it. If user reporting of messages is turned on in the Teams admin center, it also needs to be turned on the Defender portal for user reported messages to show up correctly on the User reported tab on the Submissions page.- **Defender - Report message destinations:** This applies to more than just Microsoft Teams and allows for an organization to keep their reports contained. Due to how the parameters are configured on the backend it is included in this assessment as a requirement.",
    @@ -2442,7 +2557,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This setting allows business-to-business (B2B) guests access to Microsoft Fabric, and contents that they have permissions to. With the setting turned off, B2B guest users receive an error when trying to access Power BI.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2462,7 +2578,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This setting helps organizations choose whether new external users can be invited to the organization through Power BI sharing, permissions, and subscription experiences. This setting only controls the ability to invite through Power BI.The recommended state is `Enabled for a subset of the organization` or `Disabled`.**Note:** To invite external users to the organization, the user must also have the Microsoft Entra Guest Inviter role.",
    @@ -2482,7 +2599,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This setting allows Microsoft Entra B2B guest users to have full access to the browsing experience using the left-hand navigation pane in the organization. Guest users who have been assigned workspace roles or specific item permissions will continue to have those roles and/or permissions, even if this setting is disabled.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2502,7 +2620,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Power BI enables users to share reports and materials directly on the internet from both the application's desktop version and its web user interface. This functionality generates a publicly reachable web link that doesn't necessitate authentication or the need to be an Entra ID user in order to access and view it.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2522,7 +2641,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 2",
               "AssessmentStatus": "Manual",
               "Description": "Power BI allows the integration of R and Python scripts directly into visuals. This feature allows data visualizations by incorporating custom calculations, statistical analyses, machine learning models, and more using R or Python scripts. Custom visuals can be created by embedding them directly into Power BI reports. Users can then interact with these visuals and see the results of the custom code within the Power BI interface.",
    @@ -2542,7 +2662,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Information protection tenant settings help to protect sensitive information in the Power BI tenant. Allowing and applying sensitivity labels to content ensures that information is only seen and accessed by the appropriate users.The recommended state is `Enabled` or `Enabled for a subset of the organization`.**Note:** Sensitivity labels and protection are only applied to files exported to Excel, PowerPoint, or PDF files, that are controlled by \"Export to Excel\" and \"Export reports as PowerPoint presentation or PDF documents\" settings. All other export and sharing options do not support the application of sensitivity labels and protection.**Note 2:** There are some prerequisite steps that need to be completed in order to fully utilize labeling. See [here](https://learn.microsoft.com/en-us/power-bi/enterprise/service-security-enable-data-sensitivity-labels#licensing-and-requirements).",
    @@ -2562,7 +2683,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Creating a shareable link allows a user to create a link to a report or dashboard, then add that link to an email or another messaging application. There are 3 options that can be selected when creating a shareable link:- People in your organization- People with existing access- Specific peopleThis setting solely deals with restrictions to `People in the organization`. External users by default are not included in any of these categories, and therefore cannot use any of these links regardless of the state of this setting.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2582,7 +2704,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Power BI admins can specify which users or user groups can share datasets externally with guests from a different tenant through the in-place mechanism. Disabling this setting prevents any user from sharing datasets externally by restricting the ability of users to turn on external sharing for datasets they own or manage.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2602,7 +2725,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "This setting blocks the use of resource key based authentication. The Block ResourceKey Authentication setting applies to streaming and PUSH datasets. If blocked users will not be allowed send data to streaming and PUSH datasets using the API with a resource key.The recommended state is `Enabled`.",
    @@ -2622,7 +2746,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Web apps registered in Microsoft Entra ID use an assigned service principal to access Power BI APIs without a signed-in user. This setting allows an app to use service principal authentication.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    @@ -2642,7 +2767,8 @@
           "Checks": [],
           "Attributes": [
             {
    -          "Section": "9.1",
    +          "Section": "9 Microsoft Fabric",
    +          "SubSection": "9.1 Teams settings",
               "Profile": "E3 Level 1",
               "AssessmentStatus": "Manual",
               "Description": "Service principal profiles provide a flexible solution for apps used in a multitenancy deployment. The profiles enable customer data isolation and tighter security boundaries between customers that are utilizing the app.The recommended state is `Enabled for a subset of the organization` or `Disabled`.",
    diff --git a/prowler/lib/outputs/compliance/cis/cis_m365.py b/prowler/lib/outputs/compliance/cis/cis_m365.py
    index a587d98214..addc78a104 100644
    --- a/prowler/lib/outputs/compliance/cis/cis_m365.py
    +++ b/prowler/lib/outputs/compliance/cis/cis_m365.py
    @@ -48,6 +48,7 @@ class M365CIS(ComplianceOutput):
                                 Requirements_Id=requirement.Id,
                                 Requirements_Description=requirement.Description,
                                 Requirements_Attributes_Section=attribute.Section,
    +                            Requirements_Attributes_SubSection=attribute.SubSection,
                                 Requirements_Attributes_Profile=attribute.Profile,
                                 Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
                                 Requirements_Attributes_Description=attribute.Description,
    @@ -79,6 +80,7 @@ class M365CIS(ComplianceOutput):
                             Requirements_Id=requirement.Id,
                             Requirements_Description=requirement.Description,
                             Requirements_Attributes_Section=attribute.Section,
    +                        Requirements_Attributes_SubSection=attribute.SubSection,
                             Requirements_Attributes_Profile=attribute.Profile,
                             Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
                             Requirements_Attributes_Description=attribute.Description,
    diff --git a/prowler/lib/outputs/compliance/cis/models.py b/prowler/lib/outputs/compliance/cis/models.py
    index 8ddbc3f1de..1a4764c294 100644
    --- a/prowler/lib/outputs/compliance/cis/models.py
    +++ b/prowler/lib/outputs/compliance/cis/models.py
    @@ -82,6 +82,7 @@ class M365CISModel(BaseModel):
         Requirements_Id: str
         Requirements_Description: str
         Requirements_Attributes_Section: str
    +    Requirements_Attributes_SubSection: Optional[str]
         Requirements_Attributes_Profile: str
         Requirements_Attributes_AssessmentStatus: str
         Requirements_Attributes_Description: str
    diff --git a/tests/lib/outputs/compliance/cis/cis_m365_test.py b/tests/lib/outputs/compliance/cis/cis_m365_test.py
    new file mode 100644
    index 0000000000..1c8232d73a
    --- /dev/null
    +++ b/tests/lib/outputs/compliance/cis/cis_m365_test.py
    @@ -0,0 +1,182 @@
    +from datetime import datetime
    +from io import StringIO
    +
    +from freezegun import freeze_time
    +from mock import patch
    +
    +from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
    +from prowler.lib.outputs.compliance.cis.models import M365CISModel
    +from tests.lib.outputs.compliance.fixtures import CIS_4_0_M365
    +from tests.lib.outputs.fixtures.fixtures import generate_finding_output
    +from tests.providers.m365.m365_fixtures import DOMAIN, LOCATION, TENANT_ID
    +
    +
    +class TestM365CIS:
    +    def test_output_transform(self):
    +        findings = [
    +            generate_finding_output(
    +                provider="m365",
    +                compliance={"CIS-4.0": "2.1.3"},
    +                account_name=DOMAIN,
    +                account_uid=TENANT_ID,
    +                region=LOCATION,
    +            )
    +        ]
    +        # Clear the data from CSV class
    +        output = M365CIS(findings, CIS_4_0_M365)
    +        output_data = output.data[0]
    +        assert isinstance(output_data, M365CISModel)
    +        assert output_data.Provider == "m365"
    +        assert output_data.TenantId == TENANT_ID
    +        assert output_data.Location == LOCATION
    +        assert output_data.Description == CIS_4_0_M365.Description
    +        assert output_data.Requirements_Id == CIS_4_0_M365.Requirements[0].Id
    +        assert (
    +            output_data.Requirements_Description
    +            == CIS_4_0_M365.Requirements[0].Description
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_Section
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].Section
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_SubSection
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].SubSection
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_Profile
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].Profile
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_AssessmentStatus
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].AssessmentStatus
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_Description
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].Description
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_RationaleStatement
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].RationaleStatement
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_ImpactStatement
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].ImpactStatement
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_RemediationProcedure
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].RemediationProcedure
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_AuditProcedure
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].AuditProcedure
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_AdditionalInformation
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].AdditionalInformation
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_References
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].References
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_DefaultValue
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].DefaultValue
    +        )
    +        assert output_data.Status == "PASS"
    +        assert output_data.StatusExtended == ""
    +        assert output_data.ResourceId == ""
    +        assert output_data.ResourceName == ""
    +        assert output_data.CheckId == "test-check-id"
    +        assert output_data.Muted is False
    +        # Test manual check
    +        output_data_manual = output.data[1]
    +        assert output_data_manual.Provider == "m365"
    +        assert output_data_manual.TenantId == TENANT_ID
    +        assert output_data_manual.Location == LOCATION
    +        assert output_data_manual.Description == CIS_4_0_M365.Description
    +        assert output_data_manual.Requirements_Id == CIS_4_0_M365.Requirements[1].Id
    +        assert (
    +            output_data_manual.Requirements_Description
    +            == CIS_4_0_M365.Requirements[1].Description
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_Section
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].Section
    +        )
    +        assert (
    +            output_data.Requirements_Attributes_SubSection
    +            == CIS_4_0_M365.Requirements[0].Attributes[0].SubSection
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_Profile
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].Profile
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_AssessmentStatus
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].AssessmentStatus
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_Description
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].Description
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_RationaleStatement
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].RationaleStatement
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_ImpactStatement
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].ImpactStatement
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_RemediationProcedure
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].RemediationProcedure
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_AuditProcedure
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].AuditProcedure
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_AdditionalInformation
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].AdditionalInformation
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_References
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].References
    +        )
    +        assert (
    +            output_data_manual.Requirements_Attributes_DefaultValue
    +            == CIS_4_0_M365.Requirements[1].Attributes[0].DefaultValue
    +        )
    +        assert output_data_manual.Status == "MANUAL"
    +        assert output_data_manual.StatusExtended == "Manual check"
    +        assert output_data_manual.ResourceId == "manual_check"
    +        assert output_data_manual.ResourceName == "Manual check"
    +        assert output_data_manual.CheckId == "manual"
    +        assert output_data_manual.Muted is False
    +
    +    @freeze_time(datetime.now())
    +    def test_batch_write_data_to_file(self):
    +        mock_file = StringIO()
    +        findings = [
    +            generate_finding_output(
    +                provider="m365",
    +                compliance={"CIS-4.0": "2.1.3"},
    +                account_name=DOMAIN,
    +                account_uid=TENANT_ID,
    +                region=LOCATION,
    +            )
    +        ]
    +        # Clear the data from CSV class
    +        output = M365CIS(findings, CIS_4_0_M365)
    +        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()
    +
    +        expected_csv = f"PROVIDER;DESCRIPTION;TENANTID;LOCATION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_SUBSECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_DEFAULTVALUE;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;RESOURCENAME;CHECKID;MUTED\r\nm365;The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.;00000000-0000-0000-0000-000000000000;global;{datetime.now()};2.1.3;Ensure MFA Delete is enabled on S3 buckets;2.1. Simple Storage Service (S3);;Level 1;Automated;Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.;Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.;;Perform the steps below to enable MFA delete on an S3 bucket.Note:-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.-You must use your 'root' account to enable MFA Delete on S3 buckets.**From Command line:**1. Run the s3api put-bucket-versioning command aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode;Perform the steps below to confirm MFA delete is configured on an S3 Bucket**From Console:**1. Login to the S3 console at `https://console.aws.amazon.com/s3/`2. Click the `Check` box next to the Bucket name you want to confirm3. In the window under `Properties`4. Confirm that Versioning is `Enabled`5. Confirm that MFA Delete is `Enabled`**From Command Line:**1. Run the `get-bucket-versioning aws s3api get-bucket-versioning --bucket my-bucket Output example:   Enabled Enabled\ If the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.;;By default, MFA Delete is not enabled on S3 buckets.;https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html;PASS;;;;test-check-id;False\r\nm365;The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.;00000000-0000-0000-0000-000000000000;global;{datetime.now()};2.1.4;Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive;1.1 Control Plane Node Configuration Files;;Level 1 - Master Node;Automated;Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.;The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.;;Run the below command (based on the file location on your system) on the Control Plane node. For example,  ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```;Run the below command (based on the file location on your system) on the Control Plane node. For example,  ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ```  Verify that the permissions are `600` or more restrictive.;;By default, the `kube-controller-manager.yaml` file has permissions of `640`.;https://kubernetes.io/docs/admin/kube-apiserver/;MANUAL;Manual check;manual_check;Manual check;manual;False\r\n"
    +
    +        assert content == expected_csv
    diff --git a/tests/lib/outputs/compliance/fixtures.py b/tests/lib/outputs/compliance/fixtures.py
    index 3c8b71e3cd..94c9604cf3 100644
    --- a/tests/lib/outputs/compliance/fixtures.py
    +++ b/tests/lib/outputs/compliance/fixtures.py
    @@ -243,6 +243,58 @@ CIS_1_5_AWS = Compliance(
         ],
     )
     
    +CIS_4_0_M365_NAME = "cis_4.0_m365"
    +CIS_4_0_M365 = Compliance(
    +    Framework="CIS",
    +    Provider="M365",
    +    Version="4.0",
    +    Description="The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.",
    +    Requirements=[
    +        Compliance_Requirement(
    +            Checks=[
    +                "mfa_delete_enabled",
    +            ],
    +            Id="2.1.3",
    +            Description="Ensure MFA Delete is enabled on S3 buckets",
    +            Attributes=[
    +                CIS_Requirement_Attribute(
    +                    Section="2.1. Simple Storage Service (S3)",
    +                    Profile="Level 1",
    +                    AssessmentStatus="Automated",
    +                    Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
    +                    RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
    +                    ImpactStatement="",
    +                    RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.Note:-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.-You must use your 'root' account to enable MFA Delete on S3 buckets.**From Command line:**1. Run the s3api put-bucket-versioning command aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode",
    +                    AuditProcedure="Perform the steps below to confirm MFA delete is configured on an S3 Bucket**From Console:**1. Login to the S3 console at `https://console.aws.amazon.com/s3/`2. Click the `Check` box next to the Bucket name you want to confirm3. In the window under `Properties`4. Confirm that Versioning is `Enabled`5. Confirm that MFA Delete is `Enabled`**From Command Line:**1. Run the `get-bucket-versioning aws s3api get-bucket-versioning --bucket my-bucket Output example:   Enabled Enabled\ If the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.",
    +                    AdditionalInformation="",
    +                    References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
    +                    DefaultValue="By default, MFA Delete is not enabled on S3 buckets.",
    +                )
    +            ],
    +        ),
    +        Compliance_Requirement(
    +            Checks=[],
    +            Id="2.1.4",
    +            Description="Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive",
    +            Attributes=[
    +                CIS_Requirement_Attribute(
    +                    Section="1.1 Control Plane Node Configuration Files",
    +                    Profile="Level 1 - Master Node",
    +                    AssessmentStatus="Automated",
    +                    Description="Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.",
    +                    RationaleStatement="The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.",
    +                    ImpactStatement="",
    +                    RemediationProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example,  ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```",
    +                    AuditProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example,  ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ```  Verify that the permissions are `600` or more restrictive.",
    +                    AdditionalInformation="",
    +                    References="https://kubernetes.io/docs/admin/kube-apiserver/",
    +                    DefaultValue="By default, the `kube-controller-manager.yaml` file has permissions of `640`.",
    +                )
    +            ],
    +        ),
    +    ],
    +)
    +
     MITRE_ATTACK_AWS_NAME = "mitre_attack_aws"
     MITRE_ATTACK_AWS = Compliance(
         Framework="MITRE-ATTACK",
    
    From a18dd76a5a5354e4ef19346368637d1fbead60d3 Mon Sep 17 00:00:00 2001
    From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
    Date: Mon, 19 May 2025 10:08:54 +0200
    Subject: [PATCH 338/359] chore(m365): accept all tenant domains in
     authentication (#7746)
    
    ---
     api/src/backend/api/models.py                 |   4 +-
     .../m365/lib/powershell/m365_powershell.py    |  25 +-
     prowler/providers/m365/lib/service/service.py |   4 +-
     prowler/providers/m365/m365_provider.py       | 176 ++++++-------
     prowler/providers/m365/models.py              |   9 +-
     .../lib/powershell/m365_powershell_test.py    | 232 ++++++++----------
     tests/providers/m365/m365_provider_test.py    | 124 +++++++++-
     7 files changed, 340 insertions(+), 234 deletions(-)
    
    diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py
    index 676b3b116c..61e8eb22a2 100644
    --- a/api/src/backend/api/models.py
    +++ b/api/src/backend/api/models.py
    @@ -218,9 +218,9 @@ class Provider(RowLevelSecurityProtectedModel):
     
         @staticmethod
         def validate_m365_uid(value):
    -        if not re.match(r"^[a-zA-Z0-9-]+\.onmicrosoft\.com$", value):
    +        if not re.match(r"^[a-zA-Z0-9-]+\.com$", value):
                 raise ModelValidationError(
    -                detail="M365 tenant ID must be a valid domain.",
    +                detail="M365 domain ID must be a valid domain.",
                     code="m365-uid",
                     pointer="/data/attributes/uid",
                 )
    diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py
    index f32921b001..9dbda1c01e 100644
    --- a/prowler/providers/m365/lib/powershell/m365_powershell.py
    +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py
    @@ -7,7 +7,7 @@ from prowler.lib.powershell.powershell import PowerShellSession
     from prowler.providers.m365.exceptions.exceptions import (
         M365UserNotBelongingToTenantError,
     )
    -from prowler.providers.m365.models import M365Credentials
    +from prowler.providers.m365.models import M365Credentials, M365IdentityInfo
     
     
     class M365PowerShell(PowerShellSession):
    @@ -34,7 +34,7 @@ class M365PowerShell(PowerShellSession):
             to be installed and available in the PowerShell environment.
         """
     
    -    def __init__(self, credentials: M365Credentials):
    +    def __init__(self, credentials: M365Credentials, identity: M365IdentityInfo):
             """
             Initialize a Microsoft 365 PowerShell session.
     
    @@ -46,6 +46,7 @@ class M365PowerShell(PowerShellSession):
                     for authentication.
             """
             super().__init__()
    +        self.tenant_identity = identity
             self.init_credential(credentials)
     
         def init_credential(self, credentials: M365Credentials) -> None:
    @@ -95,12 +96,24 @@ class M365PowerShell(PowerShellSession):
                 'Write-Output "$($credential.GetNetworkCredential().Password)"'
             )
     
    +        # Validate user belongs to tenant
    +        user_domain = credentials.user.split("@")[1]
    +        if not any(
    +            user_domain.endswith(domain)
    +            for domain in self.tenant_identity.tenant_domains
    +        ):
    +            raise M365UserNotBelongingToTenantError(
    +                file=os.path.basename(__file__),
    +                message=f"The user domain {user_domain} does not match any of the tenant domains: {', '.join(self.tenant_identity.tenant_domains)}",
    +            )
    +
             app = msal.ConfidentialClientApplication(
                 client_id=credentials.client_id,
                 client_credential=credentials.client_secret,
                 authority=f"https://login.microsoftonline.com/{credentials.tenant_id}",
             )
     
    +        # Validate credentials
             result = app.acquire_token_by_username_password(
                 username=credentials.user,
                 password=decrypted_password,  # Needs to be in plain text
    @@ -113,14 +126,6 @@ class M365PowerShell(PowerShellSession):
             if "access_token" not in result:
                 return False
     
    -        # Validate user credentials belong to tenant
    -        user_domain = credentials.user.split("@")[1]
    -        if not credentials.provider_id.endswith(user_domain):
    -            raise M365UserNotBelongingToTenantError(
    -                file=os.path.basename(__file__),
    -                message="The provided M365 User does not belong to the specified tenant.",
    -            )
    -
             return True
     
         def connect_microsoft_teams(self) -> dict:
    diff --git a/prowler/providers/m365/lib/service/service.py b/prowler/providers/m365/lib/service/service.py
    index b218aac283..8806c99728 100644
    --- a/prowler/providers/m365/lib/service/service.py
    +++ b/prowler/providers/m365/lib/service/service.py
    @@ -15,5 +15,7 @@ class M365Service:
     
             # Initialize PowerShell client only if credentials are available
             self.powershell = (
    -            M365PowerShell(provider.credentials) if provider.credentials else None
    +            M365PowerShell(provider.credentials, provider.identity)
    +            if provider.credentials and provider.identity
    +            else None
             )
    diff --git a/prowler/providers/m365/m365_provider.py b/prowler/providers/m365/m365_provider.py
    index 2b766171e6..a4135b0692 100644
    --- a/prowler/providers/m365/m365_provider.py
    +++ b/prowler/providers/m365/m365_provider.py
    @@ -194,20 +194,17 @@ class M365Provider(Provider):
     
             # Set up the identity
             self._identity = self.setup_identity(
    -            az_cli_auth,
                 sp_env_auth,
                 env_auth,
    -            browser_auth,
    -            client_id,
    +            self._session,
             )
     
             # Set up PowerShell session credentials
             self._credentials = self.setup_powershell(
                 env_auth=env_auth,
                 m365_credentials=m365_credentials,
    -            provider_id=self.identity.tenant_domain,
    -            init_modules=init_modules,
                 identity=self.identity,
    +            init_modules=init_modules,
             )
     
             # Audit Config
    @@ -381,9 +378,8 @@ class M365Provider(Provider):
         def setup_powershell(
             env_auth: bool = False,
             m365_credentials: dict = {},
    -        provider_id: str = None,
    -        init_modules: bool = False,
             identity: M365IdentityInfo = None,
    +        init_modules: bool = False,
         ) -> M365Credentials:
             """Gets the M365 credentials.
     
    @@ -404,7 +400,7 @@ class M365Provider(Provider):
                     client_id=m365_credentials.get("client_id", ""),
                     client_secret=m365_credentials.get("client_secret", ""),
                     tenant_id=m365_credentials.get("tenant_id", ""),
    -                provider_id=provider_id,
    +                tenant_domains=identity.tenant_domains,
                 )
             elif env_auth:
                 m365_user = getenv("M365_USER")
    @@ -422,19 +418,18 @@ class M365Provider(Provider):
                         message="Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication.",
                     )
                 credentials = M365Credentials(
    -                user=m365_user,
    -                passwd=m365_password,
                     client_id=client_id,
                     client_secret=client_secret,
                     tenant_id=tenant_id,
    -                provider_id=provider_id,
    +                tenant_domains=identity.tenant_domains,
    +                user=m365_user,
    +                passwd=m365_password,
                 )
     
             if credentials:
                 if identity:
    -                identity.identity_type = "Service Principal and User Credentials"
                     identity.user = credentials.user
    -            test_session = M365PowerShell(credentials)
    +            test_session = M365PowerShell(credentials, identity)
                 try:
                     if test_session.test_credentials(credentials):
                         if init_modules:
    @@ -704,7 +699,7 @@ class M365Provider(Provider):
                         )
     
                 # Set up the M365 session
    -            credentials = M365Provider.setup_session(
    +            session = M365Provider.setup_session(
                     az_cli_auth,
                     sp_env_auth,
                     env_auth,
    @@ -714,16 +709,35 @@ class M365Provider(Provider):
                     region_config,
                 )
     
    -            GraphServiceClient(credentials=credentials)
    +            GraphServiceClient(credentials=session)
     
                 logger.info("M365 provider: Connection to MSGraph successful")
     
    +            # Set up Identity
    +            identity = M365Provider.setup_identity(
    +                sp_env_auth,
    +                env_auth,
    +                session,
    +            )
    +
    +            if not identity:
    +                raise M365GetTokenIdentityError(
    +                    file=os.path.basename(__file__),
    +                    message="Failed to retrieve M365 identity",
    +                )
    +
    +            if provider_id not in identity.tenant_domains:
    +                raise M365InvalidProviderIdError(
    +                    file=os.path.basename(__file__),
    +                    message=f"The provider ID {provider_id} does not match any of the service principal tenant domains: {', '.join(identity.tenant_domains)}",
    +                )
    +
                 # Set up PowerShell credentials
                 if user and encrypted_password:
                     M365Provider.setup_powershell(
                         env_auth,
                         m365_credentials,
    -                    provider_id,
    +                    identity,
                     )
                 else:
                     logger.info(
    @@ -732,15 +746,6 @@ class M365Provider(Provider):
     
                 logger.info("M365 provider: Connection to PowerShell successful")
     
    -            # Check that user domain, provider_id and Graph client tenant_domain are the same
    -            if user and encrypted_password:
    -                user_domain = user.split("@")[1]
    -                if provider_id and user_domain != provider_id:
    -                    raise M365InvalidProviderIdError(
    -                        file=os.path.basename(__file__),
    -                        message=f"Provider ID {provider_id} does not match Application tenant domain {user_domain}",
    -                    )
    -
                 return Connection(is_connected=True)
     
             # Exceptions from setup_region_config
    @@ -867,13 +872,11 @@ class M365Provider(Provider):
                         message=f"Missing environment variable {env_var} required to authenticate.",
                     )
     
    +    @staticmethod
         def setup_identity(
    -        self,
    -        az_cli_auth,
             sp_env_auth,
             env_auth,
    -        browser_auth,
    -        client_id,
    +        session,
         ):
             """
             Sets up the identity for the M365 provider.
    @@ -888,7 +891,7 @@ class M365Provider(Provider):
             Returns:
                 M365IdentityInfo: An instance of M365IdentityInfo containing the identity information.
             """
    -        credentials = self.session
    +        logger.info("M365 provider: Setting up identity ...")
             # TODO: fill this object with real values not default and set to none
             identity = M365IdentityInfo()
     
    @@ -896,74 +899,75 @@ class M365Provider(Provider):
             # the identity can access AAD and retrieve the tenant domain name.
             # With cli also should be possible but right now it does not work, m365 python package issue is coming
             # At the time of writting this with az cli creds is not working, despite that is included
    -        if env_auth or az_cli_auth or sp_env_auth or browser_auth or client_id:
     
    -            async def get_m365_identity():
    -                # Trying to recover tenant domain info
    +        async def get_m365_identity(identity):
    +            # Trying to recover tenant domain info
    +            try:
    +                logger.info(
    +                    "Trying to retrieve tenant domain from AAD to populate identity structure ..."
    +                )
    +                client = GraphServiceClient(credentials=session)
    +
    +                domain_result = await client.domains.get()
    +                if getattr(domain_result, "value"):
    +                    if getattr(domain_result.value[0], "id"):
    +                        identity.tenant_domain = domain_result.value[0].id
    +                        for domain in domain_result.value:
    +                            identity.tenant_domains.append(domain.id)
    +
    +            except HttpResponseError as error:
    +                logger.error(
    +                    f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    +                )
    +                raise M365HTTPResponseError(
    +                    file=os.path.basename(__file__),
    +                    original_exception=error,
    +                )
    +            except ClientAuthenticationError as error:
    +                logger.error(
    +                    f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    +                )
    +                raise M365GetTokenIdentityError(
    +                    file=os.path.basename(__file__),
    +                    original_exception=error,
    +                )
    +            except Exception as error:
    +                logger.error(
    +                    f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    +                )
    +            # since that exception is not considered as critical, we keep filling another identity fields
    +            identity.identity_id = (
    +                getenv("AZURE_CLIENT_ID") or "Unknown user id (Missing AAD permissions)"
    +            )
    +            if sp_env_auth:
    +                identity.identity_type = "Service Principal"
    +            elif env_auth:
    +                identity.identity_type = "Service Principal and User Credentials"
    +            else:
    +                identity.identity_type = "User"
                     try:
                         logger.info(
    -                        "Trying to retrieve tenant domain from AAD to populate identity structure ..."
    +                        "Trying to retrieve user information from AAD to populate identity structure ..."
                         )
    -                    client = GraphServiceClient(credentials=credentials)
    +                    client = GraphServiceClient(credentials=session)
     
    -                    domain_result = await client.domains.get()
    -                    if getattr(domain_result, "value"):
    -                        if getattr(domain_result.value[0], "id"):
    -                            identity.tenant_domain = domain_result.value[0].id
    +                    me = await client.me.get()
    +                    if me:
    +                        if getattr(me, "user_principal_name"):
    +                            identity.identity_id = me.user_principal_name
     
    -                except HttpResponseError as error:
    -                    logger.error(
    -                        f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    -                    )
    -                    raise M365HTTPResponseError(
    -                        file=os.path.basename(__file__),
    -                        original_exception=error,
    -                    )
    -                except ClientAuthenticationError as error:
    -                    logger.error(
    -                        f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    -                    )
    -                    raise M365GetTokenIdentityError(
    -                        file=os.path.basename(__file__),
    -                        original_exception=error,
    -                    )
                     except Exception as error:
                         logger.error(
                             f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
                         )
    -                # since that exception is not considered as critical, we keep filling another identity fields
    -                if sp_env_auth or env_auth or client_id:
    -                    # The id of the sp can be retrieved from environment variables
    -                    identity.identity_id = getenv("AZURE_CLIENT_ID")
    -                    identity.identity_type = "Service Principal"
    -                # Same here, if user can access AAD, some fields are retrieved if not, default value, for az cli
    -                # should work but it doesn't, pending issue
    -                else:
    -                    identity.identity_id = "Unknown user id (Missing AAD permissions)"
    -                    identity.identity_type = "User"
    -                    try:
    -                        logger.info(
    -                            "Trying to retrieve user information from AAD to populate identity structure ..."
    -                        )
    -                        client = GraphServiceClient(credentials=credentials)
     
    -                        me = await client.me.get()
    -                        if me:
    -                            if getattr(me, "user_principal_name"):
    -                                identity.identity_id = me.user_principal_name
    +            # Retrieve tenant id from the client
    +            client = GraphServiceClient(credentials=session)
    +            organization_info = await client.organization.get()
    +            identity.tenant_id = organization_info.value[0].id
     
    -                    except Exception as error:
    -                        logger.error(
    -                            f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
    -                        )
    -
    -                # Retrieve tenant id from the client
    -                client = GraphServiceClient(credentials=credentials)
    -                organization_info = await client.organization.get()
    -                identity.tenant_id = organization_info.value[0].id
    -
    -            asyncio.get_event_loop().run_until_complete(get_m365_identity())
    -            return identity
    +        asyncio.get_event_loop().run_until_complete(get_m365_identity(identity))
    +        return identity
     
         @staticmethod
         def validate_static_credentials(
    diff --git a/prowler/providers/m365/models.py b/prowler/providers/m365/models.py
    index 198c54e33e..d0d73263b5 100644
    --- a/prowler/providers/m365/models.py
    +++ b/prowler/providers/m365/models.py
    @@ -8,7 +8,8 @@ class M365IdentityInfo(BaseModel):
         identity_id: str = ""
         identity_type: str = ""
         tenant_id: str = ""
    -    tenant_domain: str = "Unknown tenant domain (missing AAD permissions)"
    +    tenant_domain: str = "Unknown tenant domain (missing Entra permissions)"
    +    tenant_domains: list[str] = []
         location: str = ""
         user: str = None
     
    @@ -21,12 +22,12 @@ class M365RegionConfig(BaseModel):
     
     
     class M365Credentials(BaseModel):
    -    user: str = ""
    -    passwd: str = ""
         client_id: str = ""
         client_secret: str = ""
         tenant_id: str = ""
    -    provider_id: str = ""
    +    tenant_domains: list[str] = []
    +    user: str = ""
    +    passwd: str = ""
     
     
     class M365OutputOptions(ProviderOutputOptions):
    diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py
    index 66094aa581..b841602914 100644
    --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py
    +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py
    @@ -7,7 +7,7 @@ from prowler.providers.m365.exceptions.exceptions import (
         M365UserNotBelongingToTenantError,
     )
     from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell
    -from prowler.providers.m365.models import M365Credentials
    +from prowler.providers.m365.models import M365Credentials, M365IdentityInfo
     
     
     class Testm365PowerShell:
    @@ -16,9 +16,17 @@ class Testm365PowerShell:
             mock_process = MagicMock()
             mock_popen.return_value = mock_process
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
     
             with patch.object(M365PowerShell, "init_credential") as mock_init_credential:
    -            session = M365PowerShell(credentials)
    +            session = M365PowerShell(credentials, identity)
     
                 mock_popen.assert_called_once()
                 mock_init_credential.assert_called_once_with(credentials)
    @@ -29,7 +37,15 @@ class Testm365PowerShell:
         @patch("subprocess.Popen")
         def test_sanitize(self, _):
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             test_cases = [
                 ("test@example.com", "test@example.com"),
    @@ -63,7 +79,15 @@ class Testm365PowerShell:
                 client_secret="test_client_secret",
                 tenant_id="test_tenant_id",
             )
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             session.execute = MagicMock()
     
    @@ -95,9 +119,16 @@ class Testm365PowerShell:
                 client_id="test_client_id",
                 client_secret="test_client_secret",
                 tenant_id="test_tenant_id",
    -            provider_id="contoso.onmicrosoft.com",
             )
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="contoso.onmicrosoft.com",
    +            tenant_domains=["contoso.onmicrosoft.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             # Mock read_output to return the decrypted password
             session.read_output = MagicMock(return_value="decrypted_password")
    @@ -150,9 +181,16 @@ class Testm365PowerShell:
                 client_id="test_client_id",
                 client_secret="test_client_secret",
                 tenant_id="test_tenant_id",
    -            provider_id="contoso.onmicrosoft.com",
             )
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="contoso.onmicrosoft.com",
    +            tenant_domains=["contoso.onmicrosoft.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             # Mock the execute method to return the decrypted password
             def mock_execute(command, *args, **kwargs):
    @@ -168,20 +206,15 @@ class Testm365PowerShell:
                 session.test_credentials(credentials)
     
             assert exception.type == M365UserNotBelongingToTenantError
    -        assert "The provided M365 User does not belong to the specified tenant." in str(
    -            exception.value
    +        assert (
    +            "The user domain otherdomain.com does not match any of the tenant domains: contoso.onmicrosoft.com"
    +            in str(exception.value)
             )
     
    -        mock_msal.assert_called_once_with(
    -            client_id="test_client_id",
    -            client_credential="test_client_secret",
    -            authority="https://login.microsoftonline.com/test_tenant_id",
    -        )
    -        mock_msal_instance.acquire_token_by_username_password.assert_called_once_with(
    -            username="user@otherdomain.com",
    -            password="decrypted_password",
    -            scopes=["https://graph.microsoft.com/.default"],
    -        )
    +        # Verify MSAL was not called since domain validation failed first
    +        mock_msal.assert_not_called()
    +        mock_msal_instance.acquire_token_by_username_password.assert_not_called()
    +
             session.close()
     
         @patch("subprocess.Popen")
    @@ -199,9 +232,16 @@ class Testm365PowerShell:
                 client_id="test_client_id",
                 client_secret="test_client_secret",
                 tenant_id="test_tenant_id",
    -            provider_id="contoso.onmicrosoft.com",
             )
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="contoso.onmicrosoft.com",
    +            tenant_domains=["contoso.onmicrosoft.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             # Mock the execute method to return the decrypted password
             def mock_execute(command, *args, **kwargs):
    @@ -231,7 +271,15 @@ class Testm365PowerShell:
         @patch("subprocess.Popen")
         def test_remove_ansi(self, mock_popen):
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             test_cases = [
                 ("\x1b[32mSuccess\x1b[0m", "Success"),
    @@ -250,7 +298,15 @@ class Testm365PowerShell:
             mock_process = MagicMock()
             mock_popen.return_value = mock_process
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
             command = "Get-Command"
             expected_output = {"Name": "Get-Command"}
     
    @@ -261,18 +317,19 @@ class Testm365PowerShell:
     
         @patch("subprocess.Popen")
         def test_read_output(self, mock_popen):
    -        """Test the read_output method with various scenarios:
    -        - Normal stdout output
    -        - Error in stderr
    -        - Timeout in stdout
    -        - Empty output
    -        - Empty queue handling
    -        """
    -        # Setup
    +        """Test the read_output method with various scenarios"""
             mock_process = MagicMock()
             mock_popen.return_value = mock_process
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             # Test 1: Normal stdout output
             mock_process.stdout.readline.side_effect = [
    @@ -304,95 +361,6 @@ class Testm365PowerShell:
             result = session.read_output(timeout=0.1, default="timeout")
             assert result == "timeout"
     
    -        # Test 4: Empty output
    -        mock_process.stdout.readline.side_effect = [f"{session.END}\n"]
    -        mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n"
    -        result = session.read_output()
    -        assert result == ""
    -
    -        # Test 5: Empty queue handling
    -        mock_process.stdout.readline.side_effect = []  # No output at all
    -        mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n"
    -        result = session.read_output(timeout=0.1, default="empty_queue")
    -        assert result == "empty_queue"
    -
    -        # Test 6: Empty error queue handling
    -        mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"]
    -        mock_process.stderr.readline.side_effect = []  # No error output
    -        with patch("prowler.lib.logger.logger.error") as mock_error:
    -            result = session.read_output()
    -            assert result == "test output"
    -            mock_error.assert_not_called()
    -
    -        # Test 7: Both queues empty
    -        mock_process.stdout.readline.side_effect = []  # No output
    -        mock_process.stderr.readline.side_effect = []  # No error output
    -        result = session.read_output(timeout=0.1, default="both_empty")
    -        assert result == "both_empty"
    -
    -        session.close()
    -
    -    @patch("subprocess.Popen")
    -    def test_read_output_queue_empty(self, mock_popen):
    -        """Test read_output when both queues are empty"""
    -        mock_process = MagicMock()
    -        mock_popen.return_value = mock_process
    -        credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    -
    -        # Mock process to return empty queues
    -        mock_process.stdout.readline.side_effect = []  # No output
    -        mock_process.stderr.readline.side_effect = []  # No error output
    -
    -        # Test with default value
    -        result = session.read_output(timeout=0.1, default="empty_queue")
    -        assert result == "empty_queue"
    -
    -        # Test without default value
    -        result = session.read_output(timeout=0.1)
    -        assert result == ""
    -
    -        session.close()
    -
    -    @patch("subprocess.Popen")
    -    def test_read_output_error_queue_empty(self, mock_popen):
    -        """Test read_output when error queue is empty but stdout has content"""
    -        mock_process = MagicMock()
    -        mock_popen.return_value = mock_process
    -        credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    -
    -        # Mock process to return content in stdout but empty stderr
    -        mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"]
    -        mock_process.stderr.readline.side_effect = []  # No error output
    -
    -        with patch("prowler.lib.logger.logger.error") as mock_error:
    -            result = session.read_output()
    -            assert result == "test output"
    -            mock_error.assert_not_called()
    -
    -        session.close()
    -
    -    @patch("subprocess.Popen")
    -    def test_read_output_result_queue_empty(self, mock_popen):
    -        """Test read_output when result queue is empty but stderr has content"""
    -        mock_process = MagicMock()
    -        mock_popen.return_value = mock_process
    -        credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    -
    -        # Mock process to return empty stdout but content in stderr
    -        mock_process.stdout.readline.side_effect = []  # No output
    -        mock_process.stderr.readline.side_effect = [
    -            "Error message\n",
    -            f"Write-Error: {session.END}\n",
    -        ]
    -
    -        with patch("prowler.lib.logger.logger.error") as mock_error:
    -            result = session.read_output(timeout=0.1, default="default")
    -            assert result == "default"
    -            mock_error.assert_called_once_with("PowerShell error output: Error message")
    -
             session.close()
     
         @patch("subprocess.Popen")
    @@ -400,7 +368,15 @@ class Testm365PowerShell:
             mock_process = MagicMock()
             mock_popen.return_value = mock_process
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             test_cases = [
                 ('{"key": "value"}', {"key": "value"}),
    @@ -425,7 +401,15 @@ class Testm365PowerShell:
             mock_process = MagicMock()
             mock_popen.return_value = mock_process
             credentials = M365Credentials(user="test@example.com", passwd="test_password")
    -        session = M365PowerShell(credentials)
    +        identity = M365IdentityInfo(
    +            identity_id="test_id",
    +            identity_type="User",
    +            tenant_id="test_tenant",
    +            tenant_domain="example.com",
    +            tenant_domains=["example.com"],
    +            location="test_location",
    +        )
    +        session = M365PowerShell(credentials, identity)
     
             session.close()
     
    diff --git a/tests/providers/m365/m365_provider_test.py b/tests/providers/m365/m365_provider_test.py
    index 1d8c0759e6..2f30efabde 100644
    --- a/tests/providers/m365/m365_provider_test.py
    +++ b/tests/providers/m365/m365_provider_test.py
    @@ -286,6 +286,17 @@ class TestM365Provider:
                 patch(
                     "prowler.providers.m365.m365_provider.GraphServiceClient"
                 ) as mock_graph_client,
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.setup_identity",
    +                return_value=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain=DOMAIN,
    +                    tenant_domains=["test.onmicrosoft.com"],
    +                    location=LOCATION,
    +                ),
    +            ),
             ):
                 # Mock the return value of DefaultAzureCredential
                 mock_credentials = MagicMock()
    @@ -298,7 +309,7 @@ class TestM365Provider:
                 mock_session = MagicMock()
                 mock_setup_session.return_value = mock_session
     
    -            # Mock GraphServiceClient to avoid real API calls
    +            # Mock GraphServiceClient
                 mock_client = MagicMock()
                 mock_graph_client.return_value = mock_client
     
    @@ -307,6 +318,7 @@ class TestM365Provider:
                     tenant_id=str(uuid4()),
                     region="M365Global",
                     raise_on_exception=False,
    +                provider_id="test.onmicrosoft.com",
                 )
     
                 assert isinstance(test_connection, Connection)
    @@ -321,6 +333,17 @@ class TestM365Provider:
                 patch(
                     "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
                 ) as mock_validate_static_credentials,
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.setup_identity",
    +                return_value=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain=DOMAIN,
    +                    tenant_domains=["test.onmicrosoft.com"],
    +                    location=LOCATION,
    +                ),
    +            ),
             ):
                 # Mock setup_session to return a mocked session object
                 mock_session = MagicMock()
    @@ -335,6 +358,7 @@ class TestM365Provider:
                     raise_on_exception=False,
                     client_id=str(uuid4()),
                     client_secret=str(uuid4()),
    +                provider_id="test.onmicrosoft.com",
                 )
     
                 assert isinstance(test_connection, Connection)
    @@ -458,9 +482,15 @@ class TestM365Provider:
                 result = M365Provider.setup_powershell(
                     env_auth=False,
                     m365_credentials=credentials_dict,
    -                provider_id="test_provider_id",
    +                identity=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain=DOMAIN,
    +                    tenant_domains=["test.onmicrosoft.com"],
    +                    location=LOCATION,
    +                ),
                 )
    -
                 assert result.user == credentials_dict["user"]
                 assert result.passwd == credentials_dict["encrypted_password"]
     
    @@ -595,6 +625,17 @@ class TestM365Provider:
                 patch(
                     "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
                 ) as mock_validate_static_credentials,
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.setup_identity",
    +                return_value=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain="contoso.com",
    +                    tenant_domains=["contoso.com"],
    +                    location=LOCATION,
    +                ),
    +            ),
             ):
                 # Mock setup_session to return a mocked session object
                 mock_session = MagicMock()
    @@ -620,7 +661,7 @@ class TestM365Provider:
     
                 assert exception.type == M365InvalidProviderIdError
                 assert (
    -                f"Provider ID {provider_id} does not match Application tenant domain {user_domain}"
    +                f"The provider ID {provider_id} does not match any of the service principal tenant domains: {user_domain}"
                     in str(exception.value)
                 )
     
    @@ -646,7 +687,14 @@ class TestM365Provider:
                 M365Provider.setup_powershell(
                     env_auth=False,
                     m365_credentials=credentials_dict,
    -                provider_id="test_provider_id",
    +                identity=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain=DOMAIN,
    +                    tenant_domains=["test.onmicrosoft.com"],
    +                    location=LOCATION,
    +                ),
                     init_modules=False,
                 )
                 mock_init_modules.assert_not_called()
    @@ -673,7 +721,14 @@ class TestM365Provider:
                 M365Provider.setup_powershell(
                     env_auth=False,
                     m365_credentials=credentials_dict,
    -                provider_id="test_provider_id",
    +                identity=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain=DOMAIN,
    +                    tenant_domains=["test.onmicrosoft.com"],
    +                    location=LOCATION,
    +                ),
                     init_modules=True,
                 )
                 mock_init_modules.assert_called_once()
    @@ -702,8 +757,63 @@ class TestM365Provider:
                     M365Provider.setup_powershell(
                         env_auth=False,
                         m365_credentials=credentials_dict,
    -                    provider_id="test_provider_id",
    +                    identity=M365IdentityInfo(
    +                        identity_id=IDENTITY_ID,
    +                        identity_type="User",
    +                        tenant_id=TENANT_ID,
    +                        tenant_domain=DOMAIN,
    +                        tenant_domains=["test.onmicrosoft.com"],
    +                        location=LOCATION,
    +                    ),
                         init_modules=True,
                     )
     
                 assert str(exc_info.value) == "Module initialization failed"
    +
    +    def test_test_connection_provider_id_not_in_tenant_domains(self):
    +        """Test that an exception is raised when provider_id is not in tenant_domains"""
    +        with (
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.setup_session"
    +            ) as mock_setup_session,
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
    +            ) as mock_validate_static_credentials,
    +            patch(
    +                "prowler.providers.m365.m365_provider.M365Provider.setup_identity",
    +                return_value=M365IdentityInfo(
    +                    identity_id=IDENTITY_ID,
    +                    identity_type="User",
    +                    tenant_id=TENANT_ID,
    +                    tenant_domain="contoso.onmicrosoft.com",
    +                    tenant_domains=["contoso.onmicrosoft.com", "contoso.com"],
    +                    location=LOCATION,
    +                ),
    +            ),
    +        ):
    +            # Mock setup_session to return a mocked session object
    +            mock_session = MagicMock()
    +            mock_setup_session.return_value = mock_session
    +
    +            # Mock ValidateStaticCredentials to avoid real API calls
    +            mock_validate_static_credentials.return_value = None
    +
    +            provider_id = "test.onmicrosoft.com"
    +
    +            with pytest.raises(M365InvalidProviderIdError) as exception:
    +                M365Provider.test_connection(
    +                    tenant_id=str(uuid4()),
    +                    region="M365Global",
    +                    raise_on_exception=True,
    +                    client_id=str(uuid4()),
    +                    client_secret=str(uuid4()),
    +                    user="user@contoso.onmicrosoft.com",
    +                    encrypted_password="test_password",
    +                    provider_id=provider_id,
    +                )
    +
    +            assert exception.type == M365InvalidProviderIdError
    +            assert (
    +                f"The provider ID {provider_id} does not match any of the service principal tenant domains: contoso.onmicrosoft.com, contoso.com"
    +                in str(exception.value)
    +            )
    
    From f24d0efc77ef146460a25d239a8d06481f3d60d9 Mon Sep 17 00:00:00 2001
    From: Pablo Lara 
    Date: Mon, 19 May 2025 10:49:28 +0200
    Subject: [PATCH 339/359] docs: update changelog (#7773)
    
    ---
     ui/CHANGELOG.md | 5 ++++-
     1 file changed, 4 insertions(+), 1 deletion(-)
    
    diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md
    index 91dd269fd4..a3ba578082 100644
    --- a/ui/CHANGELOG.md
    +++ b/ui/CHANGELOG.md
    @@ -2,7 +2,10 @@
     
     All notable changes to the **Prowler UI** are documented in this file.
     
    -## [v1.7.0] (Prowler v5.7.0) – Not released
    +## [v1.8.0] (Prowler v5.8.0) – Not released
    +
    +---
    +## [v1.7.0] (Prowler v5.7.0)
     
     ### 🚀 Added
     
    
    From d8f80699d4e8df52f45e7f9ac8282af1f3b4aa69 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Adri=C3=A1n=20Jes=C3=BAs=20Pe=C3=B1a=20Rodr=C3=ADguez?=
     
    Date: Mon, 19 May 2025 11:07:32 +0200
    Subject: [PATCH 340/359] chore: update api changelog (#7775)
    
    ---
     api/CHANGELOG.md | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md
    index 7ecf828e69..3344a2d6db 100644
    --- a/api/CHANGELOG.md
    +++ b/api/CHANGELOG.md
    @@ -2,7 +2,7 @@
     
     All notable changes to the **Prowler API** are documented in this file.
     
    -## [v1.8.0] (Prowler UNRELEASED)
    +## [v1.8.0] (Prowler v5.7.0)
     
     ### Added
     - Added huge improvements to `/findings/metadata` and resource related filters for findings [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
    
    From 40f24b4d70750a9a8963c290c2805d80efc3d076 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?=
     
    Date: Mon, 19 May 2025 13:34:46 +0200
    Subject: [PATCH 341/359] fix(providers): Fix m365 UID validation (#7781)
    
    ---
     api/src/backend/api/models.py           |  7 ++-
     api/src/backend/api/tests/test_views.py | 65 +++++++++++++++++++++++++
     2 files changed, 71 insertions(+), 1 deletion(-)
    
    diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py
    index 61e8eb22a2..3b85d2208f 100644
    --- a/api/src/backend/api/models.py
    +++ b/api/src/backend/api/models.py
    @@ -218,7 +218,11 @@ class Provider(RowLevelSecurityProtectedModel):
     
         @staticmethod
         def validate_m365_uid(value):
    -        if not re.match(r"^[a-zA-Z0-9-]+\.com$", value):
    +        if not re.match(
    +            r"""^(?!-)[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.(?!-)[A-Za-z0-9]"""
    +            r"""(?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*\.[A-Za-z]{2,}$""",
    +            value,
    +        ):
                 raise ModelValidationError(
                     detail="M365 domain ID must be a valid domain.",
                     code="m365-uid",
    @@ -426,6 +430,7 @@ class Scan(RowLevelSecurityProtectedModel):
             PeriodicTask, on_delete=models.CASCADE, null=True, blank=True
         )
         output_location = models.CharField(blank=True, null=True, max_length=200)
    +
         # TODO: mutelist foreign key
     
         class Meta(RowLevelSecurityProtectedModel.Meta):
    diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py
    index a82348fe87..80ab44b946 100644
    --- a/api/src/backend/api/tests/test_views.py
    +++ b/api/src/backend/api/tests/test_views.py
    @@ -918,6 +918,26 @@ class TestProviderViewSet:
                         "uid": "8851db6b-42e5-4533-aa9e-30a32d67e875",
                         "alias": "test",
                     },
    +                {
    +                    "provider": "m365",
    +                    "uid": "TestingPro.onMirosoft.com",
    +                    "alias": "test",
    +                },
    +                {
    +                    "provider": "m365",
    +                    "uid": "subdomain.domain.es",
    +                    "alias": "test",
    +                },
    +                {
    +                    "provider": "m365",
    +                    "uid": "microsoft.net",
    +                    "alias": "test",
    +                },
    +                {
    +                    "provider": "m365",
    +                    "uid": "subdomain1.subdomain2.subdomain3.subdomain4.domain.net",
    +                    "alias": "test",
    +                },
                 ]
             ),
         )
    @@ -986,6 +1006,51 @@ class TestProviderViewSet:
                         "invalid_choice",
                         "provider",
                     ),
    +                (
    +                    {
    +                        "provider": "m365",
    +                        "uid": "https://test.com",
    +                        "alias": "test",
    +                    },
    +                    "m365-uid",
    +                    "uid",
    +                ),
    +                (
    +                    {
    +                        "provider": "m365",
    +                        "uid": "thisisnotadomain",
    +                        "alias": "test",
    +                    },
    +                    "m365-uid",
    +                    "uid",
    +                ),
    +                (
    +                    {
    +                        "provider": "m365",
    +                        "uid": "http://test.com",
    +                        "alias": "test",
    +                    },
    +                    "m365-uid",
    +                    "uid",
    +                ),
    +                (
    +                    {
    +                        "provider": "m365",
    +                        "uid": f"{'a' * 64}.domain.com",
    +                        "alias": "test",
    +                    },
    +                    "m365-uid",
    +                    "uid",
    +                ),
    +                (
    +                    {
    +                        "provider": "m365",
    +                        "uid": f"subdomain.{'a' * 64}.com",
    +                        "alias": "test",
    +                    },
    +                    "m365-uid",
    +                    "uid",
    +                ),
                 ]
             ),
         )
    
    From 7fd58de3bfdd75ba5393ecd6b929698a8573d6bb Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= 
    Date: Mon, 19 May 2025 15:59:42 +0200
    Subject: [PATCH 342/359] feat(export): support m365 - prowler threatscore
     (#7783)
    
    ---
     api/CHANGELOG.md                     | 1 +
     api/src/backend/tasks/jobs/export.py | 4 ++++
     2 files changed, 5 insertions(+)
    
    diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md
    index 3344a2d6db..96dc979d1e 100644
    --- a/api/CHANGELOG.md
    +++ b/api/CHANGELOG.md
    @@ -9,6 +9,7 @@ All notable changes to the **Prowler API** are documented in this file.
     - Added improvements to `/overviews` endpoints [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
     - Added new queue to perform backfill background tasks [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
     - Added new endpoints to retrieve latest findings and metadata [(#7743)](https://github.com/prowler-cloud/prowler/pull/7743).
    +- Added export support for Prowler ThreatScore in M365 [(7783)](https://github.com/prowler-cloud/prowler/pull/7783)
     
     ---
     
    diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py
    index fb405176d5..2bda9d6def 100644
    --- a/api/src/backend/tasks/jobs/export.py
    +++ b/api/src/backend/tasks/jobs/export.py
    @@ -45,6 +45,9 @@ from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_azur
     from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_gcp import (
         ProwlerThreatScoreGCP,
     )
    +from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_m365 import (
    +    ProwlerThreatScoreM365,
    +)
     from prowler.lib.outputs.csv.csv import CSV
     from prowler.lib.outputs.html.html import HTML
     from prowler.lib.outputs.ocsf.ocsf import OCSF
    @@ -85,6 +88,7 @@ COMPLIANCE_CLASS_MAP = {
         ],
         "m365": [
             (lambda name: name.startswith("cis_"), M365CIS),
    +        (lambda name: name == "prowler_threatscore_m365", ProwlerThreatScoreM365),
         ],
     }
     
    
    From 871c877a3370203e20f0d221b6e9b0c0ddbf4708 Mon Sep 17 00:00:00 2001
    From: sumit-tft <70506234+sumit-tft@users.noreply.github.com>
    Date: Tue, 20 May 2025 14:55:40 +0530
    Subject: [PATCH 343/359] fix: AWS I AM role validation when field is empty
     (#7787)
    
    Co-authored-by: Pablo Lara 
    ---
     ui/CHANGELOG.md         | 5 +++++
     ui/types/formSchemas.ts | 2 +-
     2 files changed, 6 insertions(+), 1 deletion(-)
    
    diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md
    index a3ba578082..629b18aaec 100644
    --- a/ui/CHANGELOG.md
    +++ b/ui/CHANGELOG.md
    @@ -4,7 +4,12 @@ All notable changes to the **Prowler UI** are documented in this file.
     
     ## [v1.8.0] (Prowler v5.8.0) – Not released
     
    +### 🐞 Fixes
    +
    +- Added validation to AWS IAM role. [(#7787)](https://github.com/prowler-cloud/prowler/pull/7787)
    +  
     ---
    +
     ## [v1.7.0] (Prowler v5.7.0)
     
     ### 🚀 Added
    diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts
    index 3fc096d03d..b0c64dfa24 100644
    --- a/ui/types/formSchemas.ts
    +++ b/ui/types/formSchemas.ts
    @@ -155,7 +155,7 @@ export const addCredentialsRoleFormSchema = (providerType: string) =>
             .object({
               providerId: z.string(),
               providerType: z.string(),
    -          role_arn: z.string().optional(),
    +          role_arn: z.string().nonempty("AWS Role ARN is required"),
               external_id: z.string().optional(),
               aws_access_key_id: z.string().optional(),
               aws_secret_access_key: z.string().optional(),
    
    From b3a2479fabe13eafdbfaedd6781944fd677db511 Mon Sep 17 00:00:00 2001
    From: Prowler Bot 
    Date: Tue, 20 May 2025 18:42:21 +0200
    Subject: [PATCH 344/359] chore(release): Bump version to v5.8.0 (#7788)
    
    Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
    ---
     prowler/config/config.py | 2 +-
     pyproject.toml           | 2 +-
     2 files changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/prowler/config/config.py b/prowler/config/config.py
    index 51f52ae3ca..de54add886 100644
    --- a/prowler/config/config.py
    +++ b/prowler/config/config.py
    @@ -12,7 +12,7 @@ from prowler.lib.logger import logger
     
     timestamp = datetime.today()
     timestamp_utc = datetime.now(timezone.utc).replace(tzinfo=timezone.utc)
    -prowler_version = "5.7.0"
    +prowler_version = "5.8.0"
     html_logo_url = "https://github.com/prowler-cloud/prowler/"
     square_logo_img = "https://prowler.com/wp-content/uploads/logo-html.png"
     aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png"
    diff --git a/pyproject.toml b/pyproject.toml
    index b2e9b9feb9..26cc8d967e 100644
    --- a/pyproject.toml
    +++ b/pyproject.toml
    @@ -65,7 +65,7 @@ maintainers = [{name = "Prowler Engineering", email = "engineering@prowler.com"}
     name = "prowler"
     readme = "README.md"
     requires-python = ">3.9.1,<3.13"
    -version = "5.7.0"
    +version = "5.8.0"
     
     [project.scripts]
     prowler = "prowler.__main__:prowler"
    
    From 615bacccafde85abeeb222fa986cfa901cb9c6f2 Mon Sep 17 00:00:00 2001
    From: Pablo Lara 
    Date: Wed, 21 May 2025 07:59:53 +0200
    Subject: [PATCH 345/359] chore: tweak some wording for consistency (#7794)
    
    ---
     ui/components/findings/table/finding-detail.tsx    | 4 ++--
     ui/components/providers/table/column-providers.tsx | 8 ++++++--
     2 files changed, 8 insertions(+), 4 deletions(-)
    
    diff --git a/ui/components/findings/table/finding-detail.tsx b/ui/components/findings/table/finding-detail.tsx
    index facd6a1d9f..e232b2a648 100644
    --- a/ui/components/findings/table/finding-detail.tsx
    +++ b/ui/components/findings/table/finding-detail.tsx
    @@ -115,13 +115,13 @@ export const FindingDetail = ({
                 
               
             
    - + - + diff --git a/ui/components/providers/table/column-providers.tsx b/ui/components/providers/table/column-providers.tsx index f31c199920..f16585e34b 100644 --- a/ui/components/providers/table/column-providers.tsx +++ b/ui/components/providers/table/column-providers.tsx @@ -27,7 +27,7 @@ export const ColumnProviders: ColumnDef[] = [ { accessorKey: "account", header: ({ column }) => ( - + ), cell: ({ row }) => { const { @@ -64,7 +64,11 @@ export const ColumnProviders: ColumnDef[] = [ { accessorKey: "uid", header: ({ column }) => ( - + ), cell: ({ row }) => { const { From ad39061e1af52337becc0127f86df620b6a1d140 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Wed, 21 May 2025 08:07:43 +0200 Subject: [PATCH 346/359] fix: retrieve more than 10 providers (#7793) --- ui/CHANGELOG.md | 3 ++- ui/app/(prowler)/findings/page.tsx | 2 +- ui/app/(prowler)/manage-groups/page.tsx | 4 ++-- ui/app/(prowler)/scans/page.tsx | 2 ++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 629b18aaec..52b2818551 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -7,7 +7,8 @@ All notable changes to the **Prowler UI** are documented in this file. ### 🐞 Fixes - Added validation to AWS IAM role. [(#7787)](https://github.com/prowler-cloud/prowler/pull/7787) - +- Retrieve more than 10 providers in /scans, /manage-groups and /findings pages. [(#7793)](https://github.com/prowler-cloud/prowler/pull/7793) + --- ## [v1.7.0] (Prowler v5.7.0) diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index 3615c77b3b..f137b451cc 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -43,7 +43,7 @@ export default async function Findings({ sort: encodedSort, filters, }), - getProviders({}), + getProviders({ pageSize: 50 }), getScans({}), ]); diff --git a/ui/app/(prowler)/manage-groups/page.tsx b/ui/app/(prowler)/manage-groups/page.tsx index 178baf320e..c5e5be9932 100644 --- a/ui/app/(prowler)/manage-groups/page.tsx +++ b/ui/app/(prowler)/manage-groups/page.tsx @@ -58,7 +58,7 @@ export default function ManageGroupsPage({ } const SSRAddGroupForm = async () => { - const providersResponse = await getProviders({}); + const providersResponse = await getProviders({ pageSize: 50 }); const rolesResponse = await getRoles({}); const providersData = @@ -95,7 +95,7 @@ const SSRDataEditGroup = async ({ return
    Provider group not found
    ; } - const providersResponse = await getProviders({}); + const providersResponse = await getProviders({ pageSize: 50 }); const rolesResponse = await getRoles({}); const providersList = diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx index 737d7f284b..0679139770 100644 --- a/ui/app/(prowler)/scans/page.tsx +++ b/ui/app/(prowler)/scans/page.tsx @@ -29,6 +29,7 @@ export default async function Scans({ filters: { "filter[connected]": true, }, + pageSize: 50, }); const providerInfo = @@ -42,6 +43,7 @@ export default async function Scans({ const providersCountConnected = await getProviders({ filters: { "filter[connected]": true }, + pageSize: 50, }); const thereIsNoProviders = !providersCountConnected?.data || providersCountConnected.data.length === 0; From 6f7cd85a18c1c1c57da999ea0c78bccb3b1e82dc Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 21 May 2025 12:14:30 +0545 Subject: [PATCH 347/359] chore(backport): create label on minor release (#7791) --- .github/workflows/create-backport-label.yml | 67 +++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/create-backport-label.yml diff --git a/.github/workflows/create-backport-label.yml b/.github/workflows/create-backport-label.yml new file mode 100644 index 0000000000..0bc93bd45d --- /dev/null +++ b/.github/workflows/create-backport-label.yml @@ -0,0 +1,67 @@ +name: Create Backport Label + +on: + release: + types: [published] + +jobs: + create_label: + runs-on: ubuntu-latest + permissions: + contents: write + issues: write + steps: + - name: Create backport label + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + OWNER_REPO: ${{ github.repository }} + run: | + VERSION_ONLY=${RELEASE_TAG#v} # Remove 'v' prefix if present (e.g., v3.2.0 -> 3.2.0) + + # Check if it's a minor version (X.Y.0) + if [[ "$VERSION_ONLY" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then + echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is a minor version. Proceeding to create backport label." + + TWO_DIGIT_VERSION=${VERSION_ONLY%.0} # Extract X.Y from X.Y.0 (e.g., 5.6 from 5.6.0) + + FINAL_LABEL_NAME="backport-to-v${TWO_DIGIT_VERSION}" + FINAL_DESCRIPTION="Backport PR to the v${TWO_DIGIT_VERSION} branch" + + echo "Effective label name will be: ${FINAL_LABEL_NAME}" + echo "Effective description will be: ${FINAL_DESCRIPTION}" + + # Check if the label already exists + STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${GITHUB_TOKEN}" "https://api.github.com/repos/${OWNER_REPO}/labels/${FINAL_LABEL_NAME}") + + if [ "${STATUS_CODE}" -eq 200 ]; then + echo "Label '${FINAL_LABEL_NAME}' already exists." + elif [ "${STATUS_CODE}" -eq 404 ]; then + echo "Label '${FINAL_LABEL_NAME}' does not exist. Creating it..." + # Prepare JSON data payload + JSON_DATA=$(printf '{"name":"%s","description":"%s","color":"B60205"}' "${FINAL_LABEL_NAME}" "${FINAL_DESCRIPTION}") + + CREATE_STATUS_CODE=$(curl -s -o /tmp/curl_create_response.json -w "%{http_code}" -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + --data "${JSON_DATA}" \ + "https://api.github.com/repos/${OWNER_REPO}/labels") + + CREATE_RESPONSE_BODY=$(cat /tmp/curl_create_response.json) + rm -f /tmp/curl_create_response.json + + if [ "$CREATE_STATUS_CODE" -eq 201 ]; then + echo "Label '${FINAL_LABEL_NAME}' created successfully." + else + echo "Error creating label '${FINAL_LABEL_NAME}'. Status: $CREATE_STATUS_CODE" + echo "Response: $CREATE_RESPONSE_BODY" + exit 1 + fi + else + echo "Error checking for label '${FINAL_LABEL_NAME}'. HTTP Status: ${STATUS_CODE}" + exit 1 + fi + else + echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is not a minor version. Skipping backport label creation." + exit 0 + fi From 84749df70858c8c96c14c7fd2576584319cecaf7 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 21 May 2025 08:48:36 +0200 Subject: [PATCH 348/359] feat(admincenter): add new check `admincenter_organization_customer_lockbox_enabled` (#7732) Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + prowler/compliance/m365/cis_4.0_m365.json | 4 +- .../__init__.py | 0 ...ion_customer_lockbox_enabled.metadata.json | 32 +++++ ...r_organization_customer_lockbox_enabled.py | 52 ++++++++ .../admincenter/admincenter_service.py | 30 +++++ ...enter_groups_not_public_visibility_test.py | 9 ++ ...anization_customer_lockbox_enabled_test.py | 120 ++++++++++++++++++ .../admincenter/admincenter_service_test.py | 97 +++++++++++--- ...ter_settings_password_never_expire_test.py | 9 ++ ...s_admins_reduced_license_footprint_test.py | 15 +++ ...between_two_and_four_global_admins_test.py | 12 ++ 12 files changed, 359 insertions(+), 22 deletions(-) create mode 100644 prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/__init__.py create mode 100644 prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.metadata.json create mode 100644 prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.py create mode 100644 tests/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f0f2f8a57c..f71948dc1d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update the compliance list supported for each provider from docs. [(#7694)](https://github.com/prowler-cloud/prowler/pull/7694) - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) +- Add new check `admincenter_organization_customer_lockbox_enabled`. [(#7732)](https://github.com/prowler-cloud/prowler/pull/7732) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_default_branch_requires_multiple_approvals` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) diff --git a/prowler/compliance/m365/cis_4.0_m365.json b/prowler/compliance/m365/cis_4.0_m365.json index 07f2bc2d29..92a48244ea 100644 --- a/prowler/compliance/m365/cis_4.0_m365.json +++ b/prowler/compliance/m365/cis_4.0_m365.json @@ -248,7 +248,9 @@ { "Id": "1.3.6", "Description": "Customer Lockbox is a security feature that provides an additional layer of control and transparency to customer data in Microsoft 365. It offers an approval process for Microsoft support personnel to access organization data and creates an audited trail to meet compliance requirements.", - "Checks": [], + "Checks": [ + "admincenter_organization_customer_lockbox_enabled" + ], "Attributes": [ { "Section": "1 Microsoft 365 admin center", diff --git a/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.metadata.json new file mode 100644 index 0000000000..2c0ba3ebac --- /dev/null +++ b/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "m365", + "CheckID": "admincenter_organization_customer_lockbox_enabled", + "CheckTitle": "Ensure that customer lockbox is enabled for the organization", + "CheckType": [], + "ServiceName": "admincenter", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Organization Configuration", + "Description": "Customer Lockbox ensures that Microsoft support engineers cannot access content in your tenant to perform a service operation without explicit approval. This feature provides an additional layer of control and transparency over data access requests.", + "Risk": "If Customer Lockbox is not enabled, Microsoft support personnel can access your organization's data for troubleshooting without explicit approval, potentially increasing the risk of unauthorized access or data exfiltration.", + "RelatedUrl": "https://learn.microsoft.com/en-us/azure/security/fundamentals/customer-lockbox-overview", + "Remediation": { + "Code": { + "CLI": "Set-OrganizationConfig -CustomerLockBoxEnabled $true", + "NativeIaC": "", + "Other": "1. Navigate to Microsoft 365 admin center https://admin.microsoft.com. 2. Click Settings > Org settings. 3. Select the Security & privacy tab. 4. Click Customer lockbox. 5. Check the box 'Require approval for all data access requests'. 6. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable the Customer Lockbox feature to ensure explicit approval is required before Microsoft engineers can access your data during support operations.", + "Url": "https://learn.microsoft.com/en-us/azure/security/fundamentals/customer-lockbox-overview" + } + }, + "Categories": [ + "e5" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.py b/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.py new file mode 100644 index 0000000000..532b053b14 --- /dev/null +++ b/prowler/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled.py @@ -0,0 +1,52 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( + admincenter_client, +) + + +class admincenter_organization_customer_lockbox_enabled(Check): + """ + Ensure the customer lockbox feature is enabled. + + Customer Lockbox ensures that Microsoft support engineers cannot access content + in your tenant to perform a service operation without explicit approval. This feature + provides an additional layer of control and transparency over data access requests. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check for the Customer Lockbox feature in Microsoft 365. + + This method checks if the Customer Lockbox feature is enabled in the organization configuration. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + organization_config = admincenter_client.organization_config + if organization_config: + report = CheckReportM365( + metadata=self.metadata(), + resource=organization_config, + resource_name=organization_config.name, + resource_id=organization_config.guid, + ) + report.status = "FAIL" + report.status_extended = ( + "Customer Lockbox is not enabled at organization level." + ) + + if organization_config.customer_lockbox_enabled: + report.status = "PASS" + report.status_extended = ( + "Customer Lockbox is enabled at organization level." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/admincenter/admincenter_service.py b/prowler/providers/m365/services/admincenter/admincenter_service.py index ed8e4ad4a2..09c534edf6 100644 --- a/prowler/providers/m365/services/admincenter/admincenter_service.py +++ b/prowler/providers/m365/services/admincenter/admincenter_service.py @@ -11,6 +11,11 @@ from prowler.providers.m365.m365_provider import M365Provider class AdminCenter(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) + self.organization_config = None + if self.powershell: + self.powershell.connect_exchange_online() + self.organization_config = self._get_organization_config() + self.powershell.close() loop = get_event_loop() @@ -29,6 +34,25 @@ class AdminCenter(M365Service): self.groups = attributes[1] self.domains = attributes[2] + def _get_organization_config(self): + logger.info("Microsoft365 - Getting Exchange Organization configuration...") + organization_config = None + try: + organization_configuration = self.powershell.get_organization_config() + if organization_configuration: + organization_config = Organization( + name=organization_configuration.get("Name", ""), + guid=organization_configuration.get("Guid", ""), + customer_lockbox_enabled=organization_configuration.get( + "CustomerLockboxEnabled", False + ), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return organization_config + async def _get_users(self): logger.info("M365 - Getting users...") users = {} @@ -163,3 +187,9 @@ class Group(BaseModel): class Domain(BaseModel): id: str password_validity_period: int + + +class Organization(BaseModel): + name: str + guid: str + customer_lockbox_enabled: bool diff --git a/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py b/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py index 9e8ccfbc7d..81209d67a4 100644 --- a/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_groups_not_public_visibility/admincenter_groups_not_public_visibility_test.py @@ -15,6 +15,9 @@ class Test_admincenter_groups_not_public_visibility: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, @@ -40,6 +43,9 @@ class Test_admincenter_groups_not_public_visibility: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, @@ -78,6 +84,9 @@ class Test_admincenter_groups_not_public_visibility: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_groups_not_public_visibility.admincenter_groups_not_public_visibility.admincenter_client", new=admincenter_client, diff --git a/tests/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled_test.py b/tests/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled_test.py new file mode 100644 index 0000000000..48d3f1e745 --- /dev/null +++ b/tests/providers/m365/services/admincenter/admincenter_organization_customer_lockbox_enabled/admincenter_organization_customer_lockbox_enabled_test.py @@ -0,0 +1,120 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_admincenter_organization_customer_lockbox_enabled: + def test_admincenter_no_org_config(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + admincenter_client.organization_config = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled import ( + admincenter_organization_customer_lockbox_enabled, + ) + + check = admincenter_organization_customer_lockbox_enabled() + result = check.execute() + assert len(result) == 0 + + def test_admincenter_customer_lockbox_enabled(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled import ( + admincenter_organization_customer_lockbox_enabled, + ) + from prowler.providers.m365.services.admincenter.admincenter_service import ( + Organization, + ) + + admincenter_client.organization_config = Organization( + name="test-org", + guid="org-guid", + customer_lockbox_enabled=True, + ) + + check = admincenter_organization_customer_lockbox_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Customer Lockbox is enabled at organization level." + ) + assert result[0].resource == admincenter_client.organization_config.dict() + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" + + def test_admincenter_customer_lockbox_disabled(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_organization_customer_lockbox_enabled.admincenter_organization_customer_lockbox_enabled import ( + admincenter_organization_customer_lockbox_enabled, + ) + from prowler.providers.m365.services.admincenter.admincenter_service import ( + Organization, + ) + + admincenter_client.organization_config = Organization( + name="test-org", + guid="org-guid", + customer_lockbox_enabled=False, + ) + + check = admincenter_organization_customer_lockbox_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Customer Lockbox is not enabled at organization level." + ) + assert result[0].resource == admincenter_client.organization_config.dict() + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/admincenter/admincenter_service_test.py b/tests/providers/m365/services/admincenter/admincenter_service_test.py index f72c14ce71..a7e50e8528 100644 --- a/tests/providers/m365/services/admincenter/admincenter_service_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_service_test.py @@ -1,3 +1,4 @@ +from unittest import mock from unittest.mock import patch from prowler.providers.m365.models import M365IdentityInfo @@ -5,6 +6,7 @@ from prowler.providers.m365.services.admincenter.admincenter_service import ( AdminCenter, DirectoryRole, Group, + Organization, User, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -36,6 +38,14 @@ async def mock_admincenter_get_groups(_): } +def mock_admincenter_get_organization(_): + return Organization( + guid="id-1", + name="Test", + customer_lockbox_enabled=False, + ) + + @patch( "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_users", new=mock_admincenter_get_users, @@ -48,32 +58,77 @@ async def mock_admincenter_get_groups(_): "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_groups", new=mock_admincenter_get_groups, ) +@patch( + "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_organization_config", + new=mock_admincenter_get_organization, +) class Test_AdminCenter_Service: def test_get_client(self): - admincenter_client = AdminCenter( - set_mocked_m365_provider(identity=M365IdentityInfo(tenant_domain=DOMAIN)) - ) - assert admincenter_client.client.__class__.__name__ == "GraphServiceClient" + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert admincenter_client.client.__class__.__name__ == "GraphServiceClient" def test_get_users(self): - admincenter_client = AdminCenter(set_mocked_m365_provider()) - assert len(admincenter_client.users) == 1 - assert admincenter_client.users["user-1@tenant1.es"].id == "id-1" - assert admincenter_client.users["user-1@tenant1.es"].name == "User 1" + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter(set_mocked_m365_provider()) + assert len(admincenter_client.users) == 1 + assert admincenter_client.users["user-1@tenant1.es"].id == "id-1" + assert admincenter_client.users["user-1@tenant1.es"].name == "User 1" def test_get_group_settings(self): - admincenter_client = AdminCenter(set_mocked_m365_provider()) - assert len(admincenter_client.groups) == 1 - assert admincenter_client.groups["id-1"].id == "id-1" - assert admincenter_client.groups["id-1"].name == "Test" - assert admincenter_client.groups["id-1"].visibility == "Public" + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter(set_mocked_m365_provider()) + assert len(admincenter_client.groups) == 1 + assert admincenter_client.groups["id-1"].id == "id-1" + assert admincenter_client.groups["id-1"].name == "Test" + assert admincenter_client.groups["id-1"].visibility == "Public" def test_get_directory_roles(self): - admincenter_client = AdminCenter(set_mocked_m365_provider()) - assert ( - admincenter_client.directory_roles["GlobalAdministrator"].id - == "id-directory-role" - ) - assert ( - len(admincenter_client.directory_roles["GlobalAdministrator"].members) == 0 - ) + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter(set_mocked_m365_provider()) + assert ( + admincenter_client.directory_roles["GlobalAdministrator"].id + == "id-directory-role" + ) + assert ( + len(admincenter_client.directory_roles["GlobalAdministrator"].members) + == 0 + ) + + def test_get_organization(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert admincenter_client.organization_config.guid == "id-1" + assert admincenter_client.organization_config.name == "Test" + assert ( + admincenter_client.organization_config.customer_lockbox_enabled is False + ) + admincenter_client.powershell.close() diff --git a/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py b/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py index 7c7cb7506b..e0537249a1 100644 --- a/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_settings_password_never_expire/admincenter_settings_password_never_expire_test.py @@ -15,6 +15,9 @@ class Test_admincenter_settings_password_never_expire: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, @@ -40,6 +43,9 @@ class Test_admincenter_settings_password_never_expire: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, @@ -81,6 +87,9 @@ class Test_admincenter_settings_password_never_expire: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_settings_password_never_expire.admincenter_settings_password_never_expire.admincenter_client", new=admincenter_client, diff --git a/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py b/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py index 06f807c1c2..6b93429b3d 100644 --- a/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_users_admins_reduced_license_footprint/admincenter_users_admins_reduced_license_footprint_test.py @@ -15,6 +15,9 @@ class Test_admincenter_users_admins_reduced_license_footprint: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, @@ -40,6 +43,9 @@ class Test_admincenter_users_admins_reduced_license_footprint: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, @@ -77,6 +83,9 @@ class Test_admincenter_users_admins_reduced_license_footprint: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, @@ -123,6 +132,9 @@ class Test_admincenter_users_admins_reduced_license_footprint: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, @@ -169,6 +181,9 @@ class Test_admincenter_users_admins_reduced_license_footprint: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client", new=admincenter_client, diff --git a/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py b/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py index 994dbbcf49..98cb224900 100644 --- a/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_users_between_two_and_four_global_admins/admincenter_users_between_two_and_four_global_admins_test.py @@ -15,6 +15,9 @@ class Test_admincenter_users_between_two_and_four_global_admins: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, @@ -40,6 +43,9 @@ class Test_admincenter_users_between_two_and_four_global_admins: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, @@ -91,6 +97,9 @@ class Test_admincenter_users_between_two_and_four_global_admins: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, @@ -153,6 +162,9 @@ class Test_admincenter_users_between_two_and_four_global_admins: "prowler.providers.common.provider.Provider.get_global_provider", return_value=set_mocked_m365_provider(), ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), mock.patch( "prowler.providers.m365.services.admincenter.admincenter_users_between_two_and_four_global_admins.admincenter_users_between_two_and_four_global_admins.admincenter_client", new=admincenter_client, From 1a89d6551619ad6000308f7dcae52e25672c6184 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 21 May 2025 08:49:04 +0200 Subject: [PATCH 349/359] fix(m365powershell): add `sanitize` to `test_credentials` (#7761) Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + prowler/providers/m365/lib/powershell/m365_powershell.py | 4 ++-- tests/providers/m365/lib/powershell/m365_powershell_test.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f71948dc1d..6ab55a6eb1 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. - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) - Update and upgrade CIS for all the providers [(#7738)](https://github.com/prowler-cloud/prowler/pull/7738) - Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750) +- Fix `m365_powershell test_credentials` to use sanitized credentials. [(#7761)](https://github.com/prowler-cloud/prowler/pull/7761) - Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764) --- diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 9dbda1c01e..e6a296b57c 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -87,10 +87,10 @@ class M365PowerShell(PowerShellSession): bool: True if credentials are valid and authentication succeeds, False otherwise. """ self.execute( - f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString' + f'$securePassword = "{self.sanitize(credentials.passwd)}" | ConvertTo-SecureString' ) self.execute( - f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' + f'$credential = New-Object System.Management.Automation.PSCredential("{self.sanitize(credentials.user)}", $securePassword)' ) decrypted_password = self.execute( 'Write-Output "$($credential.GetNetworkCredential().Password)"' diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py index b841602914..7bc3236433 100644 --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -145,7 +145,7 @@ class Testm365PowerShell: f'$securePassword = "{credentials.passwd}" | ConvertTo-SecureString' ) session.execute.assert_any_call( - f'$credential = New-Object System.Management.Automation.PSCredential("{credentials.user}", $securePassword)\n' + f'$credential = New-Object System.Management.Automation.PSCredential("{session.sanitize(credentials.user)}", $securePassword)' ) session.execute.assert_any_call( 'Write-Output "$($credential.GetNetworkCredential().Password)"' From 9b127eba93fb0d016947721f9c998a08c26895de Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Wed, 21 May 2025 09:14:45 +0200 Subject: [PATCH 350/359] feat(admincenter): add new check `admincenter_external_calendar_sharing_disabled` (#7733) Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + prowler/compliance/m365/cis_4.0_m365.json | 4 +- .../m365/lib/powershell/m365_powershell.py | 18 +++ .../__init__.py | 0 ...al_calendar_sharing_disabled.metadata.json | 32 +++++ ...nter_external_calendar_sharing_disabled.py | 52 ++++++++ .../admincenter/admincenter_service.py | 25 ++++ ...external_calendar_sharing_disabled_test.py | 120 ++++++++++++++++++ .../admincenter/admincenter_service_test.py | 29 +++++ 9 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/__init__.py create mode 100644 prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.metadata.json create mode 100644 prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.py create mode 100644 tests/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 6ab55a6eb1..9345caccf1 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) - Add new check `admincenter_organization_customer_lockbox_enabled`. [(#7732)](https://github.com/prowler-cloud/prowler/pull/7732) +- Add new check `admincenter_external_calendar_sharing_disabled`. [(#7733)](https://github.com/prowler-cloud/prowler/pull/7733) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_default_branch_requires_multiple_approvals` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) diff --git a/prowler/compliance/m365/cis_4.0_m365.json b/prowler/compliance/m365/cis_4.0_m365.json index 92a48244ea..98ff0e82e1 100644 --- a/prowler/compliance/m365/cis_4.0_m365.json +++ b/prowler/compliance/m365/cis_4.0_m365.json @@ -185,7 +185,9 @@ { "Id": "1.3.3", "Description": "External calendar sharing allows an administrator to enable the ability for users to share calendars with anyone outside of the organization. Outside users will be sent a URL that can be used to view the calendar.", - "Checks": [], + "Checks": [ + "admincenter_external_calendar_sharing_disabled" + ], "Attributes": [ { "Section": "1 Microsoft 365 admin center", diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index e6a296b57c..a91e25d52d 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -685,6 +685,24 @@ class M365PowerShell(PowerShellSession): """ return self.execute("Get-TransportConfig | ConvertTo-Json", json_parse=True) + def get_sharing_policy(self) -> dict: + """ + Get Exchange Online Sharing Policy. + + Retrieves the current sharing policy settings for Exchange Online. + + Returns: + dict: Sharing policy settings in JSON format. + + Example: + >>> get_sharing_policy() + { + "Identity": "Default", + "Enabled": true + } + """ + return self.execute("Get-SharingPolicy | ConvertTo-Json", json_parse=True) + # This function is used to install the required M365 PowerShell modules in Docker containers def initialize_m365_powershell_modules(): diff --git a/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/__init__.py b/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.metadata.json b/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.metadata.json new file mode 100644 index 0000000000..64f9d85c74 --- /dev/null +++ b/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "m365", + "CheckID": "admincenter_external_calendar_sharing_disabled", + "CheckTitle": "Ensure external sharing of calendars is disabled", + "CheckType": [], + "ServiceName": "admincenter", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Sharing Policy", + "Description": "Restrict the ability for users to share their calendars externally in Microsoft 365. This prevents users from sending calendar sharing links to external recipients, reducing information exposure.", + "Risk": "Allowing calendar sharing outside the organization can help attackers build knowledge of personnel availability, relationships, and activity patterns, aiding social engineering or targeted attacks.", + "RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/admin/manage/share-calendars-with-external-users?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "Set-SharingPolicy -Identity \"Default Sharing Policy\" -Enabled $False", + "NativeIaC": "", + "Other": "1. Navigate to https://admin.microsoft.com. 2. Click Settings > Org settings. 3. Select Calendar in the Services section. 4. Uncheck 'Let your users share their calendars with people outside of your organization who have Office 365 or Exchange'. 5. Click Save.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Disable external calendar sharing by setting the Default Sharing Policy to disabled.", + "Url": "https://learn.microsoft.com/en-us/microsoft-365/admin/manage/share-calendars-with-external-users?view=o365-worldwide" + } + }, + "Categories": [ + "e5" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.py b/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.py new file mode 100644 index 0000000000..ff2af49aca --- /dev/null +++ b/prowler/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled.py @@ -0,0 +1,52 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.admincenter.admincenter_client import ( + admincenter_client, +) + + +class admincenter_external_calendar_sharing_disabled(Check): + """ + Ensure that external calendar sharing is disabled for the organization. + + Disabling external calendar sharing restricts the ability for users to share their + calendars externally in Microsoft 365. This prevents users from sending calendar + sharing links to external recipients, reducing information exposure. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check for external calendar sharing in Microsoft 365. + + This method checks if external calendar sharing is disabled in the organization configuration. + + Returns: + List[CheckReportM365]: A list of reports containing the result of the check. + """ + findings = [] + sharing_policy = admincenter_client.sharing_policy + if sharing_policy: + report = CheckReportM365( + metadata=self.metadata(), + resource=sharing_policy, + resource_name=sharing_policy.name, + resource_id=sharing_policy.guid, + ) + report.status = "FAIL" + report.status_extended = ( + "External calendar sharing is enabled at the organization level." + ) + + if not sharing_policy.enabled: + report.status = "PASS" + report.status_extended = ( + "External calendar sharing is disabled at the organization level." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/admincenter/admincenter_service.py b/prowler/providers/m365/services/admincenter/admincenter_service.py index 09c534edf6..bb1cad48ba 100644 --- a/prowler/providers/m365/services/admincenter/admincenter_service.py +++ b/prowler/providers/m365/services/admincenter/admincenter_service.py @@ -12,9 +12,11 @@ class AdminCenter(M365Service): def __init__(self, provider: M365Provider): super().__init__(provider) self.organization_config = None + self.sharing_policy = None if self.powershell: self.powershell.connect_exchange_online() self.organization_config = self._get_organization_config() + self.sharing_policy = self._get_sharing_policy() self.powershell.close() loop = get_event_loop() @@ -53,6 +55,23 @@ class AdminCenter(M365Service): ) return organization_config + def _get_sharing_policy(self): + logger.info("M365 - Getting sharing policy...") + sharing_policy = None + try: + sharing_policy_data = self.powershell.get_sharing_policy() + if sharing_policy_data: + sharing_policy = SharingPolicy( + name=sharing_policy_data.get("Name", ""), + guid=sharing_policy_data.get("Guid", ""), + enabled=sharing_policy_data.get("Enabled", False), + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return sharing_policy + async def _get_users(self): logger.info("M365 - Getting users...") users = {} @@ -193,3 +212,9 @@ class Organization(BaseModel): name: str guid: str customer_lockbox_enabled: bool + + +class SharingPolicy(BaseModel): + name: str + guid: str + enabled: bool diff --git a/tests/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled_test.py b/tests/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled_test.py new file mode 100644 index 0000000000..0c76f2f696 --- /dev/null +++ b/tests/providers/m365/services/admincenter/admincenter_external_calendar_sharing_disabled/admincenter_external_calendar_sharing_disabled_test.py @@ -0,0 +1,120 @@ +from unittest import mock + +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_admincenter_external_calendar_sharing_disabled: + def test_admincenter_no_sharing_policy(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + admincenter_client.sharing_policy = None + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled import ( + admincenter_external_calendar_sharing_disabled, + ) + + check = admincenter_external_calendar_sharing_disabled() + result = check.execute() + assert len(result) == 0 + + def test_admincenter_calendar_sharing_disabled(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled import ( + admincenter_external_calendar_sharing_disabled, + ) + from prowler.providers.m365.services.admincenter.admincenter_service import ( + SharingPolicy, + ) + + admincenter_client.sharing_policy = SharingPolicy( + name="test-org", + guid="org-guid", + enabled=False, + ) + + check = admincenter_external_calendar_sharing_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "External calendar sharing is disabled at the organization level." + ) + assert result[0].resource == admincenter_client.sharing_policy.dict() + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" + + def test_admincenter_calendar_sharing_enabled(self): + admincenter_client = mock.MagicMock() + admincenter_client.audited_tenant = "audited_tenant" + admincenter_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled.admincenter_client", + new=admincenter_client, + ), + ): + from prowler.providers.m365.services.admincenter.admincenter_external_calendar_sharing_disabled.admincenter_external_calendar_sharing_disabled import ( + admincenter_external_calendar_sharing_disabled, + ) + from prowler.providers.m365.services.admincenter.admincenter_service import ( + SharingPolicy, + ) + + admincenter_client.sharing_policy = SharingPolicy( + name="test-org", + guid="org-guid", + enabled=True, + ) + + check = admincenter_external_calendar_sharing_disabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "External calendar sharing is enabled at the organization level." + ) + assert result[0].resource == admincenter_client.sharing_policy.dict() + assert result[0].resource_name == "test-org" + assert result[0].resource_id == "org-guid" + assert result[0].location == "global" diff --git a/tests/providers/m365/services/admincenter/admincenter_service_test.py b/tests/providers/m365/services/admincenter/admincenter_service_test.py index a7e50e8528..287c91d661 100644 --- a/tests/providers/m365/services/admincenter/admincenter_service_test.py +++ b/tests/providers/m365/services/admincenter/admincenter_service_test.py @@ -7,6 +7,7 @@ from prowler.providers.m365.services.admincenter.admincenter_service import ( DirectoryRole, Group, Organization, + SharingPolicy, User, ) from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider @@ -46,6 +47,14 @@ def mock_admincenter_get_organization(_): ) +def mock_admincenter_get_sharing_policy(_): + return SharingPolicy( + guid="id-1", + name="Test", + enabled=False, + ) + + @patch( "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_users", new=mock_admincenter_get_users, @@ -62,6 +71,10 @@ def mock_admincenter_get_organization(_): "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_organization_config", new=mock_admincenter_get_organization, ) +@patch( + "prowler.providers.m365.services.admincenter.admincenter_service.AdminCenter._get_sharing_policy", + new=mock_admincenter_get_sharing_policy, +) class Test_AdminCenter_Service: def test_get_client(self): with ( @@ -132,3 +145,19 @@ class Test_AdminCenter_Service: admincenter_client.organization_config.customer_lockbox_enabled is False ) admincenter_client.powershell.close() + + def test_get_sharing_policy(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + admincenter_client = AdminCenter( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert admincenter_client.sharing_policy.guid == "id-1" + assert admincenter_client.sharing_policy.name == "Test" + assert admincenter_client.sharing_policy.enabled is False + admincenter_client.powershell.close() From 2a61610fecbb823e622ce981d13a1f57e23435a1 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Wed, 21 May 2025 10:29:08 +0200 Subject: [PATCH 351/359] chore(regions_update): Changes in regions for AWS services (#7774) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- .../providers/aws/aws_regions_by_service.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index da9bba3923..43b4bb7b47 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -3460,7 +3460,8 @@ "regions": { "aws": [ "us-east-1", - "us-east-2" + "us-east-2", + "us-west-2" ], "aws-cn": [], "aws-us-gov": [] @@ -4207,6 +4208,7 @@ "entityresolution": { "regions": { "aws": [ + "af-south-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", @@ -4737,6 +4739,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -4750,6 +4753,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -4781,6 +4785,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -4794,6 +4799,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -4824,6 +4830,7 @@ "ap-southeast-2", "ap-southeast-3", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -4837,6 +4844,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -4868,6 +4876,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -4881,6 +4890,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -5882,6 +5892,7 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -5895,6 +5906,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -7814,6 +7826,7 @@ "ap-east-1", "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -9768,6 +9781,7 @@ "eu-west-1", "eu-west-2", "eu-west-3", + "il-central-1", "me-central-1", "me-south-1", "sa-east-1", From 4e845071309ff0e9421d38d56dadf18b819bbe99 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Wed, 21 May 2025 10:31:56 +0200 Subject: [PATCH 352/359] feat(entra): add new check `entra_users_mfa_capable` (#7734) Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- docs/getting-started/requirements.md | 1 + prowler/CHANGELOG.md | 1 + prowler/compliance/m365/cis_4.0_m365.json | 4 +- .../m365/services/entra/entra_service.py | 19 +++ .../entra/entra_users_mfa_capable/__init__.py | 0 .../entra_users_mfa_capable.metadata.json | 32 ++++ .../entra_users_mfa_capable.py | 45 ++++++ .../entra_users_mfa_capable_test.py | 139 ++++++++++++++++++ .../entra/microsoft365_entra_service_test.py | 6 + 9 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 prowler/providers/m365/services/entra/entra_users_mfa_capable/__init__.py create mode 100644 prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.metadata.json create mode 100644 prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.py create mode 100644 tests/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable_test.py diff --git a/docs/getting-started/requirements.md b/docs/getting-started/requirements.md index a9318228ab..29b9069013 100644 --- a/docs/getting-started/requirements.md +++ b/docs/getting-started/requirements.md @@ -247,6 +247,7 @@ Prowler for M365 requires two types of permission scopes to be set (if you want - `User.Read` (IMPORTANT: this must be set as **delegated**): Required for the sign-in. - `Sites.Read.All`: Required for SharePoint service. - `SharePointTenantSettings.Read.All`: Required for SharePoint service. + - `AuditLog.Read.All`: Required for Entra service. - **Powershell Modules Permissions**: These are set at the `M365_USER` level, so the user used to run Prowler must have one of the following roles: - `Global Reader` (recommended): this allows you to read all roles needed. diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9345caccf1..5f1416caa8 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update the compliance list supported for each provider from docs. [(#7694)](https://github.com/prowler-cloud/prowler/pull/7694) - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) +- Add new check `entra_users_mfa_capable`. [(#7734)](https://github.com/prowler-cloud/prowler/pull/7734) - Add new check `admincenter_organization_customer_lockbox_enabled`. [(#7732)](https://github.com/prowler-cloud/prowler/pull/7732) - Add new check `admincenter_external_calendar_sharing_disabled`. [(#7733)](https://github.com/prowler-cloud/prowler/pull/7733) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) diff --git a/prowler/compliance/m365/cis_4.0_m365.json b/prowler/compliance/m365/cis_4.0_m365.json index 98ff0e82e1..3a6e11b0bb 100644 --- a/prowler/compliance/m365/cis_4.0_m365.json +++ b/prowler/compliance/m365/cis_4.0_m365.json @@ -1421,7 +1421,9 @@ { "Id": "5.2.3.4", "Description": "Microsoft defines Multifactor authentication capable as being registered and enabled for a strong authentication method. The method must also be allowed by the authentication methods policy.Ensure all member users are `MFA capable`.", - "Checks": [], + "Checks": [ + "entra_users_mfa_capable" + ], "Attributes": [ { "Section": "5 Microsoft Entra admin center", diff --git a/prowler/providers/m365/services/entra/entra_service.py b/prowler/providers/m365/services/entra/entra_service.py index d752562023..3e548afdba 100644 --- a/prowler/providers/m365/services/entra/entra_service.py +++ b/prowler/providers/m365/services/entra/entra_service.py @@ -377,6 +377,19 @@ class Entra(M365Service): for member in members: user_roles_map.setdefault(member.id, []).append(role_template_id) + try: + registration_details_list = ( + await self.client.reports.authentication_methods.user_registration_details.get() + ) + registration_details = { + detail.id: detail for detail in registration_details_list.value + } + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + registration_details = {} + for user in users_list.value: users[user.id] = User( id=user.id, @@ -385,6 +398,11 @@ class Entra(M365Service): True if (user.on_premises_sync_enabled) else False ), directory_roles_ids=user_roles_map.get(user.id, []), + is_mfa_capable=( + registration_details.get(user.id, {}).is_mfa_capable + if registration_details.get(user.id, None) is not None + else False + ), ) except Exception as error: logger.error( @@ -563,6 +581,7 @@ class User(BaseModel): name: str on_premises_sync_enabled: bool directory_roles_ids: List[str] = [] + is_mfa_capable: bool = False class InvitationsFrom(Enum): diff --git a/prowler/providers/m365/services/entra/entra_users_mfa_capable/__init__.py b/prowler/providers/m365/services/entra/entra_users_mfa_capable/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.metadata.json b/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.metadata.json new file mode 100644 index 0000000000..594138cccc --- /dev/null +++ b/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "m365", + "CheckID": "entra_users_mfa_capable", + "CheckTitle": "Ensure all users are MFA capable", + "CheckType": [], + "ServiceName": "entra", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "Conditional Access Policy", + "Description": "Ensure all users are being registered and enabled for multifactor authentication.", + "Risk": "Users who are not MFA capable are more vulnerable to account compromise, as they may rely solely on single-factor authentication (typically a password), which can be easily phished or cracked.", + "RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mfa-howitworks", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "Remediation steps will depend on the status of the personnel in question or configuration of Conditional Access policies. Administrators should review each user identified on a case-by-case basis.", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure all member users are MFA capable by registering and enabling a strong authentication method that complies with the organization's authentication policy. Regularly review user status to detect gaps in MFA deployment and correct misconfigurations.", + "Url": "https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mfa-howitworks" + } + }, + "Categories": [ + "e3" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.py b/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.py new file mode 100644 index 0000000000..6196f1e9cc --- /dev/null +++ b/prowler/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable.py @@ -0,0 +1,45 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.entra.entra_client import entra_client + + +class entra_users_mfa_capable(Check): + """ + Ensure all users are MFA capable. + + This check verifies if users are MFA capable. + + The check fails if any user is not MFA capable. + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the admin MFA capable check for all users. + + Iterates over the users retrieved from the Entra client and generates a report + indicating if users are MFA capable. + + Returns: + List[CheckReportM365]: A list containing a single report with the result of the check. + """ + findings = [] + + for user in entra_client.users.values(): + report = CheckReportM365( + metadata=self.metadata(), + resource={}, + resource_name="Users", + resource_id="users", + ) + + if not user.is_mfa_capable: + report.status = "FAIL" + report.status_extended = f"User {user.name} is not MFA capable." + else: + report.status = "PASS" + report.status_extended = f"User {user.name} is MFA capable." + + findings.append(report) + + return findings diff --git a/tests/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable_test.py b/tests/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable_test.py new file mode 100644 index 0000000000..7cfbe5de0d --- /dev/null +++ b/tests/providers/m365/services/entra/entra_users_mfa_capable/entra_users_mfa_capable_test.py @@ -0,0 +1,139 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.m365.services.entra.entra_service import User +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_entra_users_mfa_capable: + def test_user_not_mfa_capable(self): + """User is not MFA capable: expected FAIL.""" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable.entra_client", + new=entra_client, + ), + ): + from prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable import ( + entra_users_mfa_capable, + ) + + user_id = str(uuid4()) + entra_client.users = { + user_id: User( + id=user_id, + name="Test User", + on_premises_sync_enabled=False, + directory_roles_ids=[], + is_mfa_capable=False, + ) + } + + check = entra_users_mfa_capable() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == "User Test User is not MFA capable." + assert result[0].resource == {} + assert result[0].resource_name == "Users" + assert result[0].resource_id == "users" + + def test_user_mfa_capable(self): + """User is MFA capable: expected PASS.""" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable.entra_client", + new=entra_client, + ), + ): + from prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable import ( + entra_users_mfa_capable, + ) + + user_id = str(uuid4()) + entra_client.users = { + user_id: User( + id=user_id, + name="Test User", + on_premises_sync_enabled=False, + directory_roles_ids=[], + is_mfa_capable=True, + ) + } + + check = entra_users_mfa_capable() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == "User Test User is MFA capable." + assert result[0].resource == {} + assert result[0].resource_name == "Users" + assert result[0].resource_id == "users" + + def test_multiple_users(self): + """Multiple users with different MFA capabilities: expected mixed results.""" + entra_client = mock.MagicMock + entra_client.audited_tenant = "audited_tenant" + entra_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable.entra_client", + new=entra_client, + ), + ): + from prowler.providers.m365.services.entra.entra_users_mfa_capable.entra_users_mfa_capable import ( + entra_users_mfa_capable, + ) + + user1_id = str(uuid4()) + user2_id = str(uuid4()) + entra_client.users = { + user1_id: User( + id=user1_id, + name="Test User 1", + on_premises_sync_enabled=False, + directory_roles_ids=[], + is_mfa_capable=True, + ), + user2_id: User( + id=user2_id, + name="Test User 2", + on_premises_sync_enabled=False, + directory_roles_ids=[], + is_mfa_capable=False, + ), + } + + check = entra_users_mfa_capable() + result = check.execute() + + assert len(result) == 2 + # First user (MFA capable) + assert result[0].status == "PASS" + assert result[0].status_extended == "User Test User 1 is MFA capable." + # Second user (not MFA capable) + assert result[1].status == "FAIL" + assert result[1].status_extended == "User Test User 2 is not MFA capable." diff --git a/tests/providers/m365/services/entra/microsoft365_entra_service_test.py b/tests/providers/m365/services/entra/microsoft365_entra_service_test.py index 98fbed8e35..46e92aa1f1 100644 --- a/tests/providers/m365/services/entra/microsoft365_entra_service_test.py +++ b/tests/providers/m365/services/entra/microsoft365_entra_service_test.py @@ -121,18 +121,21 @@ async def mock_entra_get_users(_): name="User 1", directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], on_premises_sync_enabled=True, + is_mfa_capable=True, ), "user-2": User( id="user-2", name="User 2", directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], on_premises_sync_enabled=False, + is_mfa_capable=False, ), "user-3": User( id="user-3", name="User 3", directory_roles_ids=[AdminRoles.GLOBAL_ADMINISTRATOR.value], on_premises_sync_enabled=True, + is_mfa_capable=False, ), } @@ -278,12 +281,14 @@ class Test_Entra_Service: assert entra_client.users["user-1"].directory_roles_ids == [ AdminRoles.GLOBAL_ADMINISTRATOR.value ] + assert entra_client.users["user-1"].is_mfa_capable assert entra_client.users["user-1"].on_premises_sync_enabled assert entra_client.users["user-2"].id == "user-2" assert entra_client.users["user-2"].name == "User 2" assert entra_client.users["user-2"].directory_roles_ids == [ AdminRoles.GLOBAL_ADMINISTRATOR.value ] + assert not entra_client.users["user-2"].is_mfa_capable assert not entra_client.users["user-2"].on_premises_sync_enabled assert entra_client.users["user-3"].id == "user-3" assert entra_client.users["user-3"].name == "User 3" @@ -291,3 +296,4 @@ class Test_Entra_Service: AdminRoles.GLOBAL_ADMINISTRATOR.value ] assert entra_client.users["user-3"].on_premises_sync_enabled + assert not entra_client.users["user-3"].is_mfa_capable From acdf4209419bf6c2e8c34d6a6267e91fe6781286 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Wed, 21 May 2025 10:47:32 +0200 Subject: [PATCH 353/359] feat: profile page (#7780) Co-authored-by: Pablo Lara --- ui/CHANGELOG.md | 6 + ui/actions/roles/roles.ts | 32 +++++ ui/actions/users/tenants.ts | 28 ++++ ui/actions/users/users.ts | 34 ++++- ui/app/(prowler)/profile/page.tsx | 76 +++++++--- .../findings/table/delta-indicator.tsx | 2 +- .../ui/content-layout/content-layout.tsx | 4 +- ui/components/ui/user-nav/user-nav.tsx | 2 +- ui/components/users/profile/index.ts | 7 +- .../users/profile/membership-item.tsx | 27 ++++ .../users/profile/memberships-card.tsx | 44 ++++++ ui/components/users/profile/role-item.tsx | 94 +++++++++++++ ui/components/users/profile/roles-card.tsx | 41 ++++++ .../users/profile/skeleton-user-info.tsx | 132 ++++++++++-------- .../users/profile/user-basic-info-card.tsx | 90 ++++++++++++ ui/components/users/profile/user-info.tsx | 77 ---------- ui/lib/permissions.ts | 44 ++++++ ui/types/users/users.ts | 101 +++++++++++++- 18 files changed, 678 insertions(+), 163 deletions(-) create mode 100644 ui/actions/users/tenants.ts create mode 100644 ui/components/users/profile/membership-item.tsx create mode 100644 ui/components/users/profile/memberships-card.tsx create mode 100644 ui/components/users/profile/role-item.tsx create mode 100644 ui/components/users/profile/roles-card.tsx create mode 100644 ui/components/users/profile/user-basic-info-card.tsx delete mode 100644 ui/components/users/profile/user-info.tsx create mode 100644 ui/lib/permissions.ts diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 52b2818551..39a1fbca22 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to the **Prowler UI** are documented in this file. ## [v1.8.0] (Prowler v5.8.0) – Not released + +### 🚀 Added + +- New profile page with details about the user and their roles. [(#7780)](https://github.com/prowler-cloud/prowler/pull/7780) + ### 🐞 Fixes - Added validation to AWS IAM role. [(#7787)](https://github.com/prowler-cloud/prowler/pull/7787) @@ -13,6 +18,7 @@ All notable changes to the **Prowler UI** are documented in this file. ## [v1.7.0] (Prowler v5.7.0) + ### 🚀 Added - Add a new chart to show the split between passed and failed findings. [(#7680)](https://github.com/prowler-cloud/prowler/pull/7680) diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index e63558d1b9..d0dd07bd9a 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -73,6 +73,38 @@ export const getRoleInfoById = async (roleId: string) => { } }; +export const getRolesByIds = async (roleIds: string[]) => { + if (!roleIds || roleIds.length === 0) { + return { data: [] }; + } + + const headers = await getAuthHeaders({ contentType: false }); + const url = new URL(`${apiBaseUrl}/roles`); + + // Add filter for role IDs + url.searchParams.append("filter[id__in]", roleIds.join(",")); + // Request all results on a single page with reasonable size + url.searchParams.append("page[size]", "100"); + + try { + const response = await fetch(url.toString(), { + method: "GET", + headers, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch roles: ${response.statusText}`); + } + + const data = await response.json(); + return parseStringify(data); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching roles by IDs:", error); + return { data: [] }; + } +}; + export const addRole = async (formData: FormData) => { const headers = await getAuthHeaders({ contentType: true }); diff --git a/ui/actions/users/tenants.ts b/ui/actions/users/tenants.ts new file mode 100644 index 0000000000..0901345852 --- /dev/null +++ b/ui/actions/users/tenants.ts @@ -0,0 +1,28 @@ +import { revalidatePath } from "next/cache"; + +import { apiBaseUrl, getAuthHeaders, parseStringify } from "@/lib/helper"; + +export const getAllTenants = async () => { + const headers = await getAuthHeaders({ contentType: false }); + const url = new URL(`${apiBaseUrl}/tenants`); + + try { + const response = await fetch(url.toString(), { + method: "GET", + headers, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch tenants data: ${response.statusText}`); + } + + const data = await response.json(); + const parsedData = parseStringify(data); + revalidatePath("/profile"); + return parsedData; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching tenants:", error); + return undefined; + } +}; diff --git a/ui/actions/users/users.ts b/ui/actions/users/users.ts index b826c5fcc7..c47c58ebbf 100644 --- a/ui/actions/users/users.ts +++ b/ui/actions/users/users.ts @@ -184,9 +184,9 @@ export const deleteUser = async (formData: FormData) => { } }; -export const getProfileInfo = async () => { +export const getUserInfo = async () => { const headers = await getAuthHeaders({ contentType: false }); - const url = new URL(`${apiBaseUrl}/users/me`); + const url = new URL(`${apiBaseUrl}/users/me?include=roles`); try { const response = await fetch(url.toString(), { @@ -208,3 +208,33 @@ export const getProfileInfo = async () => { return undefined; } }; + +export const getUserMemberships = async (userId: string) => { + if (!userId) { + return { data: [] }; + } + + const headers = await getAuthHeaders({ contentType: false }); + const url = new URL(`${apiBaseUrl}/users/${userId}/memberships`); + url.searchParams.append("page[size]", "100"); + + try { + const response = await fetch(url.toString(), { + method: "GET", + headers, + }); + + if (!response.ok) { + throw new Error( + `Failed to fetch user memberships: ${response.statusText}`, + ); + } + + const data = await response.json(); + return parseStringify(data); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching user memberships:", error); + return { data: [] }; + } +}; diff --git a/ui/app/(prowler)/profile/page.tsx b/ui/app/(prowler)/profile/page.tsx index 6ea66ded18..b78d9e8439 100644 --- a/ui/app/(prowler)/profile/page.tsx +++ b/ui/app/(prowler)/profile/page.tsx @@ -1,36 +1,74 @@ import React, { Suspense } from "react"; -import { getProfileInfo } from "@/actions/users/users"; +import { getAllTenants } from "@/actions/users/tenants"; +import { getUserInfo } from "@/actions/users/users"; +import { getUserMemberships } from "@/actions/users/users"; import { ContentLayout } from "@/components/ui"; -import { SkeletonUserInfo } from "@/components/users/profile"; -import { UserInfo } from "@/components/users/profile/user-info"; -import { UserProfileProps } from "@/types"; +import { UserBasicInfoCard } from "@/components/users/profile"; +import { MembershipsCard } from "@/components/users/profile/memberships-card"; +import { RolesCard } from "@/components/users/profile/roles-card"; +import { SkeletonUserInfo } from "@/components/users/profile/skeleton-user-info"; +import { RoleDetail, TenantDetailData } from "@/types/users/users"; export default async function Profile() { return ( -
    -
    -
    -
    - }> - - -
    -
    -
    +
    + }> + +
    ); } const SSRDataUser = async () => { - const userProfile: UserProfileProps = await getProfileInfo(); + const userProfile = await getUserInfo(); + if (!userProfile?.data) { + return null; + } + + const roleDetails = + userProfile.included?.filter((item: any) => item.type === "roles") || []; + + const roleDetailsMap = roleDetails.reduce( + (acc: Record, role: RoleDetail) => { + acc[role.id] = role; + return acc; + }, + {} as Record, + ); + + const memberships = await getUserMemberships(userProfile.data.id); + const tenants = await getAllTenants(); + + const tenantsMap = tenants?.data?.reduce( + (acc: Record, tenant: TenantDetailData) => { + acc[tenant.id] = tenant; + return acc; + }, + {} as Record, + ); + + const userMembershipIds = + userProfile.data.relationships?.memberships?.data?.map( + (membership: { id: string }) => membership.id, + ) || []; + + const userTenant = tenants?.data?.find((tenant: TenantDetailData) => + tenant.relationships?.memberships?.data?.some( + (membership: { id: string }) => userMembershipIds.includes(membership.id), + ), + ); return ( - <> -

    User Info

    - - +
    + + + +
    ); }; diff --git a/ui/components/findings/table/delta-indicator.tsx b/ui/components/findings/table/delta-indicator.tsx index 3336c18702..86f89b02a6 100644 --- a/ui/components/findings/table/delta-indicator.tsx +++ b/ui/components/findings/table/delta-indicator.tsx @@ -37,7 +37,7 @@ export const DeltaIndicator = ({ delta }: DeltaIndicatorProps) => { delta === "new" ? "bg-system-severity-high" : delta === "changed" - ? "bg-system-severity-medium" + ? "bg-system-severity-low" : "bg-gray-500", )} /> diff --git a/ui/components/ui/content-layout/content-layout.tsx b/ui/components/ui/content-layout/content-layout.tsx index b073c1c477..f1fdb13a57 100644 --- a/ui/components/ui/content-layout/content-layout.tsx +++ b/ui/components/ui/content-layout/content-layout.tsx @@ -1,6 +1,6 @@ import { Suspense, use } from "react"; -import { getProfileInfo } from "@/actions/users/users"; +import { getUserInfo } from "@/actions/users/users"; import { Navbar } from "../nav-bar/navbar"; import { SkeletonContentLayout } from "./skeleton-content-layout"; @@ -11,7 +11,7 @@ interface ContentLayoutProps { } export function ContentLayout({ title, icon, children }: ContentLayoutProps) { - const user = use(getProfileInfo()); + const user = use(getUserInfo()); return ( <> diff --git a/ui/components/ui/user-nav/user-nav.tsx b/ui/components/ui/user-nav/user-nav.tsx index b5023a9ece..58ff0b9abf 100644 --- a/ui/components/ui/user-nav/user-nav.tsx +++ b/ui/components/ui/user-nav/user-nav.tsx @@ -77,7 +77,7 @@ export const UserNav = ({ user }: { user?: UserProfileProps }) => { - + Account diff --git a/ui/components/users/profile/index.ts b/ui/components/users/profile/index.ts index 07aeca9b89..02cdd56c9d 100644 --- a/ui/components/users/profile/index.ts +++ b/ui/components/users/profile/index.ts @@ -1,2 +1,5 @@ -export * from "./skeleton-user-info"; -export * from "./user-info"; +export * from "./membership-item"; +export * from "./memberships-card"; +export * from "./role-item"; +export * from "./roles-card"; +export * from "./user-basic-info-card"; diff --git a/ui/components/users/profile/membership-item.tsx b/ui/components/users/profile/membership-item.tsx new file mode 100644 index 0000000000..f9d28a9f7d --- /dev/null +++ b/ui/components/users/profile/membership-item.tsx @@ -0,0 +1,27 @@ +import { Chip } from "@nextui-org/react"; + +import { DateWithTime } from "@/components/ui/entities"; +import { MembershipDetailData } from "@/types/users/users"; + +export const MembershipItem = ({ + membership, + tenantName, +}: { + membership: MembershipDetailData; + tenantName: string; +}) => ( +
    +
    +
    + + {membership.attributes.role} + +

    {tenantName}

    +
    +
    +
    + Joined on: + +
    +
    +); diff --git a/ui/components/users/profile/memberships-card.tsx b/ui/components/users/profile/memberships-card.tsx new file mode 100644 index 0000000000..c752882156 --- /dev/null +++ b/ui/components/users/profile/memberships-card.tsx @@ -0,0 +1,44 @@ +import { Card, CardBody, CardHeader } from "@nextui-org/react"; + +import { MembershipDetailData, TenantDetailData } from "@/types/users/users"; + +import { MembershipItem } from "./membership-item"; + +export const MembershipsCard = ({ + memberships, + tenantsMap, +}: { + memberships: MembershipDetailData[]; + tenantsMap: Record; +}) => { + return ( + + +
    +

    Organizations

    +

    + Organizations this user is associated with +

    +
    +
    + + {memberships.length === 0 ? ( +
    No memberships found.
    + ) : ( +
    + {memberships.map((membership) => ( + + ))} +
    + )} +
    +
    + ); +}; diff --git a/ui/components/users/profile/role-item.tsx b/ui/components/users/profile/role-item.tsx new file mode 100644 index 0000000000..27c056843c --- /dev/null +++ b/ui/components/users/profile/role-item.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { Chip } from "@nextui-org/react"; +import { Ban, Check } from "lucide-react"; +import { useState } from "react"; + +import { CustomButton } from "@/components/ui/custom/custom-button"; +import { getRolePermissions } from "@/lib/permissions"; +import { RoleData, RoleDetail } from "@/types/users/users"; + +interface PermissionItemProps { + enabled: boolean; + label: string; +} + +export const PermissionIcon = ({ enabled }: { enabled: boolean }) => ( + + {enabled ? : } + +); + +const PermissionItem = ({ enabled, label }: PermissionItemProps) => ( +
    + + {label} +
    +); + +export const RoleItem = ({ + role, + roleDetail, +}: { + role: RoleData; + roleDetail?: RoleDetail; +}) => { + const [isExpanded, setIsExpanded] = useState(false); + + if (!roleDetail) { + return ( + + {role.id} + + ); + } + + const { attributes } = roleDetail; + const roleName = attributes?.name || role.id; + const permissionState = attributes?.permission_state || ""; + const detailsId = `role-details-${role.id}`; + + const permissions = getRolePermissions(attributes); + + return ( +
    +
    +
    + + {roleName} + + + {permissionState} + +
    + + setIsExpanded(!isExpanded)} + className="text-blue-500" + color="transparent" + size="sm" + > + {isExpanded ? "Hide details" : "Show details"} + +
    + + {isExpanded && ( +
    +
    + {permissions.map(({ key, label, enabled }) => ( + + ))} +
    +
    + )} +
    + ); +}; diff --git a/ui/components/users/profile/roles-card.tsx b/ui/components/users/profile/roles-card.tsx new file mode 100644 index 0000000000..5135c41528 --- /dev/null +++ b/ui/components/users/profile/roles-card.tsx @@ -0,0 +1,41 @@ +import { Card, CardBody, CardHeader } from "@nextui-org/react"; + +import { RoleData, RoleDetail } from "@/types/users/users"; + +import { RoleItem } from "./role-item"; + +export const RolesCard = ({ + roles, + roleDetails, +}: { + roles: RoleData[]; + roleDetails: Record; +}) => { + return ( + + +
    +

    Active roles

    +

    + Roles assigned to this user account +

    +
    +
    + + {roles.length === 0 ? ( +
    No roles assigned.
    + ) : ( +
    + {roles.map((role) => ( + + ))} +
    + )} +
    +
    + ); +}; diff --git a/ui/components/users/profile/skeleton-user-info.tsx b/ui/components/users/profile/skeleton-user-info.tsx index 6bd52c322e..fec5f68f19 100644 --- a/ui/components/users/profile/skeleton-user-info.tsx +++ b/ui/components/users/profile/skeleton-user-info.tsx @@ -1,64 +1,82 @@ -import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react"; +import { Card, CardBody, Skeleton } from "@nextui-org/react"; export const SkeletonUserInfo = () => { - const rows = 4; - return ( - - - -
    -
    -
    - -
    - {/* Header Skeleton */} -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    - - {/* Row Skeletons */} - {Array.from({ length: rows }).map((_, index) => ( -
    - {/* Provider Name */} -
    - -
    -
    - -
    -
    -
    - {/* Percent Passing */} - -
    -
    - {/* Failing Checks */} - -
    -
    - {/* Total Resources */} - -
    +
    + {/* User Information */} + + +
    + {/* Name */} +
    +

    Name:

    + +
    - ))} -
    -
    -
    + {/* Email */} +
    +

    Email:

    + +
    +
    +
    + {/* Company */} +
    +

    Company:

    + +
    +
    +
    + {/* Date Joined */} +
    +

    + Date Joined: +

    + +
    +
    +
    + {/* Tenant ID */} +
    +

    + Tenant ID: +

    + +
    +
    +
    +
    + + + + {/* Roles */} + + +

    Roles

    +
    + {[1, 2, 3].map((i) => ( + +
    +
    + ))} +
    +
    +
    + + {/* Memberships */} + + +

    Memberships

    +
    + {[1, 2].map((i) => ( + +
    +
    + ))} +
    +
    +
    +
    ); }; diff --git a/ui/components/users/profile/user-basic-info-card.tsx b/ui/components/users/profile/user-basic-info-card.tsx new file mode 100644 index 0000000000..5c4ea0bbbd --- /dev/null +++ b/ui/components/users/profile/user-basic-info-card.tsx @@ -0,0 +1,90 @@ +"use client"; + +import { Card, CardBody, Divider, Tooltip } from "@nextui-org/react"; +import { CircleUserRound } from "lucide-react"; +import { useState } from "react"; + +import { CopyIcon, DoneIcon } from "@/components/icons"; +import { CustomButton } from "@/components/ui/custom/custom-button"; +import { DateWithTime } from "@/components/ui/entities"; +import { UserDataWithRoles } from "@/types/users/users"; + +const TenantIdCopy = ({ id }: { id: string }) => { + const [copied, setCopied] = useState(false); + + const handleCopyTenantId = () => { + navigator.clipboard.writeText(id); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
    +

    + Active organization ID: +

    +
    + + + + {id} + + {copied ? ( + + ) : ( + + )} + + +
    +
    + ); +}; + +export const UserBasicInfoCard = ({ + user, + tenantId, +}: { + user: UserDataWithRoles; + tenantId: string; +}) => { + const { name, email, company_name, date_joined } = user.attributes; + + return ( + + +
    + +
    +

    Name:

    + {name} +
    +
    +

    Email:

    + {email} +
    +
    +

    Company:

    + {company_name} +
    +
    +

    + Date Joined: +

    + + + +
    + + +
    +
    +
    + ); +}; diff --git a/ui/components/users/profile/user-info.tsx b/ui/components/users/profile/user-info.tsx deleted file mode 100644 index ac44770a04..0000000000 --- a/ui/components/users/profile/user-info.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client"; - -import { Card, CardBody } from "@nextui-org/react"; - -import { DateWithTime } from "@/components/ui/entities"; -import { UserProfileProps } from "@/types"; - -export const UserInfo = ({ - user, -}: { - user: UserProfileProps["data"] | null; -}) => { - if (!user || !user.attributes) { - return ( - - -
    -
    -

    Name:

    - - -
    -
    -

    Email:

    - - -
    -
    -

    Company:

    - - -
    -
    -

    - Date Joined: -

    - - -
    -
    -
    - Unable to load user information. -
    - Please check your API connection. -
    -
    -
    - ); - } - - const { name, email, company_name, date_joined } = user.attributes; - - return ( - - -
    -
    -

    Name:

    - {name} -
    -
    -

    Email:

    - {email} -
    -
    -

    Company:

    - {company_name} -
    -
    -

    - Date Joined: -

    - - - -
    -
    -
    -
    - ); -}; diff --git a/ui/lib/permissions.ts b/ui/lib/permissions.ts new file mode 100644 index 0000000000..6e0862637d --- /dev/null +++ b/ui/lib/permissions.ts @@ -0,0 +1,44 @@ +import { RolePermissionAttributes } from "@/types/users/users"; + +/** + * Get the permissions for a user role + * @param attributes - The attributes of the user role + * @returns The permissions for the user role + */ +export const getRolePermissions = (attributes: RolePermissionAttributes) => { + const permissions = [ + { + key: "manage_users", + label: "Manage Users", + enabled: attributes.manage_users, + }, + { + key: "manage_account", + label: "Manage Account", + enabled: attributes.manage_account, + }, + { + key: "manage_providers", + label: "Manage Providers", + enabled: attributes.manage_providers, + }, + { + key: "manage_scans", + label: "Manage Scans", + enabled: attributes.manage_scans, + }, + + { + key: "manage_integrations", + label: "Manage Integrations", + enabled: attributes.manage_integrations, + }, + { + key: "unlimited_visibility", + label: "Unlimited Visibility", + enabled: attributes.unlimited_visibility, + }, + ]; + + return permissions; +}; diff --git a/ui/types/users/users.ts b/ui/types/users/users.ts index 61a92ae70e..993f1bf286 100644 --- a/ui/types/users/users.ts +++ b/ui/types/users/users.ts @@ -5,7 +5,7 @@ export interface UserAttributes { date_joined: string; } -export interface Membership { +export interface MembershipData { type: string; id: string; } @@ -17,7 +17,7 @@ export interface MembershipMeta { export interface UserRelationships { memberships: { meta: MembershipMeta; - data: Membership[]; + data: MembershipData[]; }; } @@ -50,3 +50,100 @@ export interface TokenData { export interface SignInResponse { data: TokenData; } + +export interface RoleData { + type: "roles"; + id: string; +} + +export type PermissionKey = + | "manage_users" + | "manage_account" + | "manage_providers" + | "manage_scans" + | "manage_integrations" + | "unlimited_visibility"; + +export type RolePermissionAttributes = Pick< + RoleDetail["attributes"], + PermissionKey +>; + +export interface RoleDetail { + id: string; + type: "roles"; + attributes: { + name: string; + manage_users: boolean; + manage_account: boolean; + manage_providers: boolean; + manage_scans: boolean; + manage_integrations: boolean; + unlimited_visibility: boolean; + permission_state?: string; + inserted_at?: string; + updated_at?: string; + }; +} + +export interface MembershipDetailData { + id: string; + type: "memberships"; + attributes: { + role: string; + date_joined: string; + [key: string]: any; + }; + relationships: { + tenant: { + data: { + type: string; + id: string; + }; + }; + [key: string]: any; + }; +} + +export interface UserDataWithRoles + extends Omit { + attributes: UserAttributes & { + role?: { + name: string; + }; + }; + relationships: { + memberships: UserRelationships["memberships"]; + roles?: { + meta: { + count: number; + }; + data: RoleData[]; + }; + }; +} + +export interface UserInfoProps { + user: UserDataWithRoles | null; + roleDetails?: RoleDetail[]; + membershipDetails?: MembershipDetailData[]; +} + +export interface TenantDetailData { + type: string; + id: string; + attributes: { + name: string; + }; + relationships: { + memberships: { + meta: { + count: number; + }; + data: Array<{ + type: string; + id: string; + }>; + }; + }; +} From 021e243adafbd3e5b26612bcb5434648fa9997a9 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 21 May 2025 10:49:18 +0200 Subject: [PATCH 354/359] feat(kubernetes): support `HTTPS_PROXY` and `K8S_SKIP_TLS_VERIFY` (#7720) --- docs/tutorials/kubernetes/misc.md | 20 +++++++ .../kubernetes/kubernetes_provider.py | 31 +++++++++- .../kubernetes/kubernetes_provider_test.py | 58 ++++++++++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/kubernetes/misc.md b/docs/tutorials/kubernetes/misc.md index 2554bc712b..0d1edb936b 100644 --- a/docs/tutorials/kubernetes/misc.md +++ b/docs/tutorials/kubernetes/misc.md @@ -21,3 +21,23 @@ To specify the namespace(s) to be scanned, use the `--namespace` flag followed b ```console prowler --namespace namespace1 namespace2 ``` + +## Proxy and TLS Verification + +If your Kubernetes cluster is only accessible via an internal proxy, Prowler will respect the `HTTPS_PROXY` or `https_proxy` environment variable: + +```console +export HTTPS_PROXY=http://my.internal.proxy:8888 +prowler kubernetes ... +``` + +If you need to skip TLS verification for internal proxies, you can set the `K8S_SKIP_TLS_VERIFY` environment variable: + +```console +export K8S_SKIP_TLS_VERIFY=true +prowler kubernetes ... +``` + +This will allow Prowler to connect to the cluster even if the proxy uses a self-signed certificate. + +These environment variables are supported both when using an external `kubeconfig` and in in-cluster mode. diff --git a/prowler/providers/kubernetes/kubernetes_provider.py b/prowler/providers/kubernetes/kubernetes_provider.py index 160ef4e897..20b019780a 100644 --- a/prowler/providers/kubernetes/kubernetes_provider.py +++ b/prowler/providers/kubernetes/kubernetes_provider.py @@ -2,6 +2,7 @@ import os from typing import Union from colorama import Fore, Style +from kubernetes.client import ApiClient, Configuration from kubernetes.client.exceptions import ApiException from kubernetes.config.config_exception import ConfigException from requests.exceptions import Timeout @@ -286,9 +287,21 @@ class KubernetesProvider(Provider): "user": "service-account-name", }, } - return KubernetesSession( - api_client=client.ApiClient(), context=context + # Ensure proxy settings are respected + configuration = Configuration.get_default_copy() + proxy = os.environ.get("HTTPS_PROXY") or os.environ.get( + "https_proxy" ) + if proxy: + configuration.proxy = proxy + # Prevent SSL verification issues with internal proxies + if os.environ.get("K8S_SKIP_TLS_VERIFY", "false").lower() == "true": + configuration.verify_ssl = False + + return KubernetesSession( + api_client=ApiClient(configuration), context=context + ) + if context: contexts = config.list_kube_config_contexts( config_file=kubeconfig_file @@ -302,7 +315,19 @@ class KubernetesProvider(Provider): context = config.list_kube_config_contexts( config_file=kubeconfig_file )[1] - return KubernetesSession(api_client=client.ApiClient(), context=context) + # Ensure proxy settings are respected + configuration = Configuration.get_default_copy() + proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy") + if proxy: + configuration.proxy = proxy + + # Prevent SSL verification issues with internal proxies + if os.environ.get("K8S_SKIP_TLS_VERIFY", "false").lower() == "true": + configuration.verify_ssl = False + + return KubernetesSession( + api_client=ApiClient(configuration), context=context + ) except parser.ParserError as parser_error: logger.critical( diff --git a/tests/providers/kubernetes/kubernetes_provider_test.py b/tests/providers/kubernetes/kubernetes_provider_test.py index 411693117d..d21792aeb0 100644 --- a/tests/providers/kubernetes/kubernetes_provider_test.py +++ b/tests/providers/kubernetes/kubernetes_provider_test.py @@ -1,5 +1,5 @@ from argparse import Namespace -from unittest.mock import patch +from unittest.mock import MagicMock, patch from kubernetes.config.config_exception import ConfigException @@ -353,3 +353,59 @@ class TestKubernetesProvider: ) assert isinstance(session, KubernetesSession) assert session.context["context"]["cluster"] == "cli-cluster-name" + + def test_kubernetes_provider_proxy_from_env(self, monkeypatch): + monkeypatch.setenv("HTTPS_PROXY", "http://my.internal.proxy:8888") + + captured = {} + + def fake_api_client(configuration): + captured["proxy"] = getattr(configuration, "proxy", None) + return MagicMock() + + with ( + patch( + "kubernetes.config.load_kube_config", + side_effect=ConfigException("No kubeconfig"), + ), + patch("kubernetes.config.load_incluster_config", return_value=None), + patch( + "prowler.providers.kubernetes.kubernetes_provider.ApiClient", + side_effect=fake_api_client, + ), + patch( + "prowler.providers.kubernetes.kubernetes_provider.KubernetesProvider.get_all_namespaces", + return_value=["default"], + ), + ): + KubernetesProvider.setup_session() + + assert captured["proxy"] == "http://my.internal.proxy:8888" + + def test_kubernetes_provider_disable_tls_verification(self, monkeypatch): + monkeypatch.setenv("K8S_SKIP_TLS_VERIFY", "true") + + captured = {} + + def fake_api_client(configuration): + captured["verify_ssl"] = getattr(configuration, "verify_ssl", True) + return MagicMock() + + with ( + patch( + "kubernetes.config.load_kube_config", + side_effect=ConfigException("No kubeconfig"), + ), + patch("kubernetes.config.load_incluster_config", return_value=None), + patch( + "prowler.providers.kubernetes.kubernetes_provider.ApiClient", + side_effect=fake_api_client, + ), + patch( + "prowler.providers.kubernetes.kubernetes_provider.KubernetesProvider.get_all_namespaces", + return_value=["default"], + ), + ): + KubernetesProvider.setup_session() + + assert captured["verify_ssl"] is False From c6259b6c75d1c91e693d94013720eb35ad365c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 21 May 2025 11:08:52 +0200 Subject: [PATCH 355/359] fix(dashboard): remove typo from subscribe cards (#7792) --- dashboard/__main__.py | 2 +- dashboard/lib/layouts.py | 2 +- dashboard/pages/overview.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dashboard/__main__.py b/dashboard/__main__.py index 3bfb4c623a..dac536ccdf 100644 --- a/dashboard/__main__.py +++ b/dashboard/__main__.py @@ -161,7 +161,7 @@ def update_nav_bar(pathname): html.Span( [ html.Img(src="assets/favicon.ico", className="w-5"), - "Subscribe to prowler SaaS", + "Subscribe to Prowler Cloud", ], className="flex items-center gap-x-3 text-white", ), diff --git a/dashboard/lib/layouts.py b/dashboard/lib/layouts.py index 73d3ec5bcf..f1b4408c38 100644 --- a/dashboard/lib/layouts.py +++ b/dashboard/lib/layouts.py @@ -132,7 +132,7 @@ def create_layout_compliance( html.A( [ html.Img(src="assets/favicon.ico", className="w-5 mr-3"), - html.Span("Subscribe to prowler SaaS"), + html.Span("Subscribe to Prowler Cloud"), ], href="https://prowler.pro/", target="_blank", diff --git a/dashboard/pages/overview.py b/dashboard/pages/overview.py index 3daccd039b..2688281af2 100644 --- a/dashboard/pages/overview.py +++ b/dashboard/pages/overview.py @@ -1342,13 +1342,13 @@ def filter_data( "m365", m365_provider_logo, "Accounts", full_filtered_data ) - # Subscribe to prowler SaaS card + # Subscribe to Prowler Cloud card subscribe_card = [ html.Div( html.A( [ html.Img(src="assets/favicon.ico", className="w-5 mr-3"), - html.Span("Subscribe to prowler SaaS"), + html.Span("Subscribe to Prowler Cloud"), ], href="https://prowler.pro/", target="_blank", From 4e958fdf39b5f7e45c8376163f398693f1d20d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 21 May 2025 11:09:47 +0200 Subject: [PATCH 356/359] feat(kubernetes): add CIS 1.11 compliance framework (#7790) Co-authored-by: MrCloudSec --- README.md | 2 +- dashboard/compliance/cis_1_11_kubernetes.py | 24 + prowler/CHANGELOG.md | 10 + .../kubernetes/cis_1.11_kubernetes.json | 2980 +++++++++++++++++ 4 files changed, 3015 insertions(+), 1 deletion(-) create mode 100644 dashboard/compliance/cis_1_11_kubernetes.py create mode 100644 prowler/compliance/kubernetes/cis_1.11_kubernetes.json diff --git a/README.md b/README.md index 82db510e66..ccab5e285b 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ prowler dashboard | AWS | 564 | 82 | 34 | 10 | | GCP | 79 | 13 | 7 | 3 | | Azure | 140 | 18 | 8 | 3 | -| Kubernetes | 83 | 7 | 4 | 7 | +| Kubernetes | 83 | 7 | 5 | 7 | | GitHub | 3 | 2 | 1 | 0 | | M365 | 44 | 2 | 2 | 0 | | NHN (Unofficial) | 6 | 2 | 1 | 0 | diff --git a/dashboard/compliance/cis_1_11_kubernetes.py b/dashboard/compliance/cis_1_11_kubernetes.py new file mode 100644 index 0000000000..94558f33ad --- /dev/null +++ b/dashboard/compliance/cis_1_11_kubernetes.py @@ -0,0 +1,24 @@ +import warnings + +from dashboard.common_methods import get_section_containers_cis + +warnings.filterwarnings("ignore") + + +def get_table(data): + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 5f1416caa8..9c0f1cb886 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to the **Prowler SDK** are documented in this file. +## [5.8.0] (Prowler v5.8.0) + +### Added +- Add CIS 1.11 compliance framework for Kubernetes. [(#7790)](https://github.com/prowler-cloud/prowler/pull/7790) +- Support `HTTPS_PROXY` and `K8S_SKIP_TLS_VERIFY` in Kubernetes. [(#7720)](https://github.com/prowler-cloud/prowler/pull/7720) + +### Fixed + +--- + ## [v5.7.0] (Prowler v5.7.0) ### Added diff --git a/prowler/compliance/kubernetes/cis_1.11_kubernetes.json b/prowler/compliance/kubernetes/cis_1.11_kubernetes.json new file mode 100644 index 0000000000..d091e42bae --- /dev/null +++ b/prowler/compliance/kubernetes/cis_1.11_kubernetes.json @@ -0,0 +1,2980 @@ +{ + "Framework": "CIS", + "Version": "1.11.1", + "Provider": "Kubernetes", + "Description": "This CIS Kubernetes Benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes v1.28 - v1.31", + "Requirements": [ + { + "Id": "1.1.1", + "Description": "Ensure that the API server pod specification file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the API server pod specification file has permissions of `600` or more restrictive.", + "RationaleStatement": "The API server pod specification file controls various parameters that set the behavior of the API server. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-apiserver.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-apiserver.yaml ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the `kube-apiserver.yaml` file has permissions of `640`." + } + ] + }, + { + "Id": "1.1.2", + "Description": "Ensure that the API server pod specification file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the API server pod specification file ownership is set to `root:root`.", + "RationaleStatement": "The API server pod specification file controls various parameters that set the behavior of the API server. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/manifests/kube-apiserver.yaml ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the `kube-apiserver.yaml` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.3", + "Description": "Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.", + "RationaleStatement": "The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the `kube-controller-manager.yaml` file has permissions of `640`." + } + ] + }, + { + "Id": "1.1.4", + "Description": "Ensure that the controller manager pod specification file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the controller manager pod specification file ownership is set to `root:root`.", + "RationaleStatement": "The controller manager pod specification file controls various parameters that set the behavior of various components of the master node. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/manifests/kube-controller-manager.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager", + "DefaultValue": "By default, `kube-controller-manager.yaml` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.5", + "Description": "Ensure that the scheduler pod specification file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the scheduler pod specification file has permissions of `600` or more restrictive.", + "RationaleStatement": "The scheduler pod specification file controls various parameters that set the behavior of the Scheduler service in the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-scheduler.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-scheduler.yaml ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-scheduler/", + "DefaultValue": "By default, `kube-scheduler.yaml` file has permissions of `640`." + } + ] + }, + { + "Id": "1.1.6", + "Description": "Ensure that the scheduler pod specification file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the scheduler pod specification file ownership is set to `root:root`.", + "RationaleStatement": "The scheduler pod specification file controls various parameters that set the behavior of the `kube-scheduler` service in the master node. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/manifests/kube-scheduler.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/manifests/kube-scheduler.yaml ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-scheduler/", + "DefaultValue": "By default, `kube-scheduler.yaml` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.7", + "Description": "Ensure that the etcd pod specification file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `600` or more restrictive.", + "RationaleStatement": "The etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` controls various parameters that set the behavior of the `etcd` service in the master node. etcd is a highly-available key-value store which Kubernetes uses for persistent storage of all of its REST API object. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/etcd.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/etcd.yaml ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `640`." + } + ] + }, + { + "Id": "1.1.8", + "Description": "Ensure that the etcd pod specification file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`.", + "RationaleStatement": "The etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` controls various parameters that set the behavior of the `etcd` service in the master node. etcd is a highly-available key-value store which Kubernetes uses for persistent storage of all of its REST API object. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/manifests/etcd.yaml ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/manifests/etcd.yaml ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.9", + "Description": "Ensure that the Container Network Interface file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the Container Network Interface files have permissions of `600` or more restrictive.", + "RationaleStatement": "Container Network Interface provides various networking options for overlay networking. You should consult their documentation and restrict their respective file permissions to maintain the integrity of those files. Those files should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/cluster-administration/networking/", + "DefaultValue": "NA" + } + ] + }, + { + "Id": "1.1.10", + "Description": "Ensure that the Container Network Interface file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the Container Network Interface files have ownership set to `root:root`.", + "RationaleStatement": "Container Network Interface provides various networking options for overlay networking. You should consult their documentation and restrict their respective file permissions to maintain the integrity of those files. Those files should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/cluster-administration/networking/", + "DefaultValue": "NA" + } + ] + }, + { + "Id": "1.1.11", + "Description": "Ensure that the etcd data directory permissions are set to 700 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the etcd data directory has permissions of `700` or more restrictive.", + "RationaleStatement": "etcd is a highly-available key-value store used by Kubernetes deployments for persistent storage of all of its REST API objects. This data directory should be protected from any unauthorized reads or writes. It should not be readable or writable by any group members or the world.", + "ImpactStatement": "None", + "RemediationProcedure": "On the etcd server node, get the etcd data directory, passed as an argument `--data-dir`, from the below command: ``` ps -ef | grep etcd ``` Run the below command (based on the etcd data directory found above). For example, ``` chmod 700 /var/lib/etcd ```", + "AuditProcedure": "On the etcd server node, get the etcd data directory, passed as an argument `--data-dir`, from the below command: ``` ps -ef | grep etcd ``` Run the below command (based on the etcd data directory found above). For example, ``` stat -c %a /var/lib/etcd ``` Verify that the permissions are `700` or more restrictive.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/configuration.html#data-dir:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, etcd data directory has permissions of `755`." + } + ] + }, + { + "Id": "1.1.12", + "Description": "Ensure that the etcd data directory ownership is set to etcd:etcd", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the etcd data directory ownership is set to `etcd:etcd`.", + "RationaleStatement": "etcd is a highly-available key-value store used by Kubernetes deployments for persistent storage of all of its REST API objects. This data directory should be protected from any unauthorized reads or writes. It should be owned by `etcd:etcd`.", + "ImpactStatement": "None", + "RemediationProcedure": "On the etcd server node, get the etcd data directory, passed as an argument `--data-dir`, from the below command: ``` ps -ef | grep etcd ``` Run the below command (based on the etcd data directory found above). For example, ``` chown etcd:etcd /var/lib/etcd ```", + "AuditProcedure": "On the etcd server node, get the etcd data directory, passed as an argument `--data-dir`, from the below command: ``` ps -ef | grep etcd ``` Run the below command (based on the etcd data directory found above). For example, ``` stat -c %U:%G /var/lib/etcd ``` Verify that the ownership is set to `etcd:etcd`.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/configuration.html#data-dir:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, etcd data directory ownership is set to `etcd:etcd`." + } + ] + }, + { + "Id": "1.1.13", + "Description": "Ensure that the default administrative credential file permissions are set to 600", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `admin.conf` file (and `super-admin.conf` file, where it exists) have permissions of `600`.", + "RationaleStatement": "As part of initial cluster setup, default kubeconfig files are created to be used by the administrator of the cluster. These files contain private keys and certificates which allow for privileged access to the cluster. You should restrict their file permissions to maintain the integrity and confidentiality of the file(s). The file(s) should be readable and writable by only the administrators on the system.", + "ImpactStatement": "None.", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/admin.conf ``` On Kubernetes 1.29+ the `super-admin.conf` file should also be modified, if present. For example, ``` chmod 600 /etc/kubernetes/super-admin.conf ```", + "AuditProcedure": "Run the following command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/admin.conf ``` On Kubernetes version 1.29 and higher run the following command as well :- ``` stat -c %a /etc/kubernetes/super-admin.conf ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/:https://raesene.github.io/blog/2024/01/06/when-is-admin-not-admin/", + "DefaultValue": "By default, admin.conf and super-admin.conf have permissions of `600`." + } + ] + }, + { + "Id": "1.1.14", + "Description": "Ensure that the default administrative credential file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `admin.conf` (and `super-admin.conf` file, where it exists) file ownership is set to `root:root`.", + "RationaleStatement": "As part of initial cluster setup, default kubeconfig files are created to be used by the administrator of the cluster. These files contain private keys and certificates which allow for privileged access to the cluster. You should set their file ownership to maintain the integrity and confidentiality of the file. The file(s) should be owned by `root:root`.", + "ImpactStatement": "None.", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/admin.conf ``` On Kubernetes 1.29+ the super-admin.conf file should also be modified, if present. For example, ``` chown root:root /etc/kubernetes/super-admin.conf ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/admin.conf ``` On Kubernetes version 1.29 and higher run the following command as well :- ``` stat -c %U:%G /etc/kubernetes/super-admin.conf ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubeadm/:https://raesene.github.io/blog/2024/01/06/when-is-admin-not-admin/", + "DefaultValue": "By default, `admin.conf` and `super-admin.conf` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.15", + "Description": "Ensure that the scheduler.conf file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `scheduler.conf` file has permissions of `600` or more restrictive.", + "RationaleStatement": "The `scheduler.conf` file is the kubeconfig file for the Scheduler. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/scheduler.conf ```", + "AuditProcedure": "Run the following command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/scheduler.conf ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/", + "DefaultValue": "By default, `scheduler.conf` has permissions of `640`." + } + ] + }, + { + "Id": "1.1.16", + "Description": "Ensure that the scheduler.conf file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `scheduler.conf` file ownership is set to `root:root`.", + "RationaleStatement": "The `scheduler.conf` file is the kubeconfig file for the Scheduler. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/scheduler.conf ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/scheduler.conf ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubeadm/", + "DefaultValue": "By default, `scheduler.conf` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.17", + "Description": "Ensure that the controller-manager.conf file permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `controller-manager.conf` file has permissions of 600 or more restrictive.", + "RationaleStatement": "The `controller-manager.conf` file is the kubeconfig file for the Controller Manager. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/controller-manager.conf ```", + "AuditProcedure": "Run the following command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/controller-manager.conf ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/", + "DefaultValue": "By default, `controller-manager.conf` has permissions of `640`." + } + ] + }, + { + "Id": "1.1.18", + "Description": "Ensure that the controller-manager.conf file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `controller-manager.conf` file ownership is set to `root:root`.", + "RationaleStatement": "The `controller-manager.conf` file is the kubeconfig file for the Controller Manager. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown root:root /etc/kubernetes/controller-manager.conf ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %U:%G /etc/kubernetes/controller-manager.conf ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/", + "DefaultValue": "By default, `controller-manager.conf` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "1.1.19", + "Description": "Ensure that the Kubernetes PKI directory and file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the Kubernetes PKI directory and file ownership is set to `root:root`.", + "RationaleStatement": "Kubernetes makes use of a number of certificates as part of its operation. You should set the ownership of the directory containing the PKI information and all files in that directory to maintain their integrity. The directory and files should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chown -R root:root /etc/kubernetes/pki/ ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` ls -laR /etc/kubernetes/pki/ ``` Verify that the ownership of all files and directories in this hierarchy is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the /etc/kubernetes/pki/ directory and all of the files and directories contained within it, are set to be owned by the root user." + } + ] + }, + { + "Id": "1.1.20", + "Description": "Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that Kubernetes PKI certificate files have permissions of `644` or more restrictive.", + "RationaleStatement": "Kubernetes makes use of a number of certificate files as part of the operation of its components. The permissions on these files should be set to `644` or more restrictive to protect their integrity and confidentiality.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod -R 644 /etc/kubernetes/pki/*.crt ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c '%a' /etc/kubernetes/pki/*.crt ``` Verify that the permissions are `644` or more restrictive. or ``` ls -l /etc/kubernetes/pki/*.crt ``` Verify -rw------", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the certificates used by Kubernetes are set to have permissions of `644`" + } + ] + }, + { + "Id": "1.1.21", + "Description": "Ensure that the Kubernetes PKI key file permissions are set to 600", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.1 Control Plane Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that Kubernetes PKI key files have permissions of `600`.", + "RationaleStatement": "Kubernetes makes use of a number of key files as part of the operation of its components. The permissions on these files should be set to `600` to protect their integrity and confidentiality.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod -R 600 /etc/kubernetes/pki/*.key ```", + "AuditProcedure": "Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c '%a' /etc/kubernetes/pki/*.key ``` Verify that the permissions are `600` or more restrictive. or ``` ls -l /etc/kubernetes/pki/*.key ``` Verify that the permissions are `-rw------`", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, the keys used by Kubernetes are set to have permissions of `600`" + } + ] + }, + { + "Id": "1.2.1", + "Description": "Ensure that the --anonymous-auth argument is set to false", + "Checks": [ + "apiserver_anonymous_requests" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Disable anonymous requests to the API server.", + "RationaleStatement": "When enabled, requests that are not rejected by other configured authentication methods are treated as anonymous requests. These requests are then served by the API server. You should rely on authentication to authorize access and disallow anonymous requests. If you are using RBAC authorization, it is generally considered reasonable to allow anonymous access to the API Server for health checks and discovery purposes, and hence this recommendation is not scored. However, you should consider whether anonymous discovery is an acceptable risk for your purposes.", + "ImpactStatement": "Anonymous requests will be rejected.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the below parameter. ``` --anonymous-auth=false ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--anonymous-auth` argument is set to `false`. Alternative Audit Method ``` kubectl get pod -nkube-system -lcomponent=kube-apiserver -o=jsonpath='{range .items[*]}{.spec.containers[*].command} {\\}{end}' | grep '--anonymous-auth' | grep -i false ``` If the exit code is '1', then the control isn't present / failed", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/:https://kubernetes.io/docs/admin/authentication/#anonymous-requests", + "DefaultValue": "By default, anonymous access is enabled." + } + ] + }, + { + "Id": "1.2.2", + "Description": "Ensure that the --token-auth-file parameter is not set", + "Checks": [ + "apiserver_no_token_auth_file" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not use token based authentication.", + "RationaleStatement": "The token-based authentication utilizes static tokens to authenticate requests to the apiserver. The tokens are stored in clear-text in a file on the apiserver, and cannot be revoked or rotated without restarting the apiserver. Hence, do not use static token-based authentication.", + "ImpactStatement": "You will have to configure and use alternate authentication mechanisms such as certificates. Static token based authentication could not be used.", + "RemediationProcedure": "Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and remove the `--token-auth-file=` parameter.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--token-auth-file` argument does not exist. Alternative Audit Method ``` kubectl get pod -nkube-system -lcomponent=kube-apiserver -o=jsonpath='{range .items[*]}{.spec.containers[*].command} {\\}{end}' | grep '--token-auth-file' | grep -i false ``` If the exit code is '1', then the control isn't present / failed", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/authentication/#static-token-file:https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, `--token-auth-file` argument is not set." + } + ] + }, + { + "Id": "1.2.3", + "Description": "Ensure that the DenyServiceExternalIPs is set", + "Checks": [ + "apiserver_deny_service_external_ips" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "This admission controller rejects all net-new usage of the Service field externalIPs.", + "RationaleStatement": "Most users do not need the ability to set the `externalIPs` field for a `Service` at all, and cluster admins should consider disabling this functionality by enabling the `DenyServiceExternalIPs` admission controller. Clusters that do need to allow this functionality should consider using some custom policy to manage its usage.", + "ImpactStatement": "When enabled, users of the cluster may not create new Services which use externalIPs and may not add new values to externalIPs on existing Service objects.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and append the Kubernetes API server flag --enable-admission-plugins with the DenyServiceExternalIPs plugin. Note, the Kubernetes API server flag --enable-admission-plugins takes a comma-delimited list of admission control plugins to be enabled, even if they are in the list of plugins enabled by default. ``` kube-apiserver --enable-admission-plugins=DenyServiceExternalIPs ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `DenyServiceExternalIPs' argument exist as a string value in --enable-admission-plugins.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/:https://kubernetes.io/docs/admin/kube-apiserver/", + "DefaultValue": "By default, --enable-admission-plugins=DenyServiceExternalIP argument is not set, and the use of externalIPs is authorized." + } + ] + }, + { + "Id": "1.2.4", + "Description": "Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate", + "Checks": [ + "apiserver_kubelet_tls_auth" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Enable certificate based kubelet authentication.", + "RationaleStatement": "The apiserver, by default, does not authenticate itself to the kubelet's HTTPS endpoints. The requests from the apiserver are treated anonymously. You should set up certificate-based kubelet authentication to ensure that the apiserver authenticates itself to kubelets when submitting requests.", + "ImpactStatement": "You require TLS to be configured on apiserver as well as kubelets.", + "RemediationProcedure": "Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the kubelet client certificate and key parameters as below. ``` --kubelet-client-certificate= --kubelet-client-key= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--kubelet-client-certificate` and `--kubelet-client-key` arguments exist and they are set as appropriate. Alternative Audit ``` kubectl get pod -nkube-system -lcomponent=kube-apiserver -o=jsonpath='{range .items[*]}{.spec.containers[*].command} {\\}{end}' | grep '--kubelet-client-certificate' | grep -i false ``` If the exit code is '1', then the control isn't present / failed", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/:https://kubernetes.io/docs/admin/kubelet-authentication-authorization/:https://kubernetes.io/docs/concepts/cluster-administration/master-node-communication/#apiserver---kubelet", + "DefaultValue": "By default, certificate-based kubelet authentication is not set." + } + ] + }, + { + "Id": "1.2.5", + "Description": "Ensure that the --kubelet-certificate-authority argument is set as appropriate", + "Checks": [ + "apiserver_kubelet_cert_auth" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Verify kubelet's certificate before establishing connection.", + "RationaleStatement": "The connections from the apiserver to the kubelet are used for fetching logs for pods, attaching (through kubectl) to running pods, and using the kubelet’s port-forwarding functionality. These connections terminate at the kubelet’s HTTPS endpoint. By default, the apiserver does not verify the kubelet’s serving certificate, which makes the connection subject to man-in-the-middle attacks, and unsafe to run over untrusted and/or public networks.", + "ImpactStatement": "You require TLS to be configured on apiserver as well as kubelets.", + "RemediationProcedure": "Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--kubelet-certificate-authority` parameter to the path to the cert file for the certificate authority. ``` --kubelet-certificate-authority= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--kubelet-certificate-authority` argument exists and is set as appropriate. Alternative Audit ``` kubectl get pod -nkube-system -lcomponent=kube-apiserver -o=jsonpath='{range .items[]}{.spec.containers[].command} {\\}{end}' | grep '--kubelet-certificate-authority' | grep -i false ``` If the exit code is '1', then the control isn't present / failed", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/:https://kubernetes.io/docs/admin/kubelet-authentication-authorization/:https://kubernetes.io/docs/concepts/cluster-administration/master-node-communication/#apiserver---kubelet", + "DefaultValue": "By default, `--kubelet-certificate-authority` argument is not set." + } + ] + }, + { + "Id": "1.2.6", + "Description": "Ensure that the --authorization-mode argument is not set to AlwaysAllow", + "Checks": [ + "apiserver_auth_mode_not_always_allow" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not always authorize all requests.", + "RationaleStatement": "The API Server, can be configured to allow all requests. This mode should not be used on any production cluster.", + "ImpactStatement": "Only authorized requests will be served.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--authorization-mode` parameter to values other than `AlwaysAllow`. One such example could be as below. ``` --authorization-mode=RBAC ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--authorization-mode` argument exists and is not set to `AlwaysAllow`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/admin/authorization/", + "DefaultValue": "By default, `AlwaysAllow` is not enabled." + } + ] + }, + { + "Id": "1.2.7", + "Description": "Ensure that the --authorization-mode argument includes Node", + "Checks": [ + "apiserver_auth_mode_include_node" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Restrict kubelet nodes to reading only objects associated with them.", + "RationaleStatement": "The `Node` authorization mode only allows kubelets to read `Secret`, `ConfigMap`, `PersistentVolume`, and `PersistentVolumeClaim` objects associated with their nodes.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--authorization-mode` parameter to a value that includes `Node`. ``` --authorization-mode=Node,RBAC ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--authorization-mode` argument exists and is set to a value to include `Node`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-apiserver/:https://kubernetes.io/docs/admin/authorization/node/:https://github.com/kubernetes/kubernetes/pull/46076:https://acotten.com/post/kube17-security", + "DefaultValue": "By default, `Node` authorization is not enabled." + } + ] + }, + { + "Id": "1.2.8", + "Description": "Ensure that the --authorization-mode argument includes RBAC", + "Checks": [ + "apiserver_auth_mode_include_rbac" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Turn on Role Based Access Control.", + "RationaleStatement": "Role Based Access Control (RBAC) allows fine-grained control over the operations that different entities can perform on different objects in the cluster. It is recommended to use the RBAC authorization mode.", + "ImpactStatement": "When RBAC is enabled you will need to ensure that appropriate RBAC settings (including Roles, RoleBindings and ClusterRoleBindings) are configured to allow appropriate access.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--authorization-mode` parameter to a value that includes `RBAC`, for example: ``` --authorization-mode=Node,RBAC ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--authorization-mode` argument exists and is set to a value to include `RBAC`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/access-authn-authz/rbac/", + "DefaultValue": "By default, `RBAC` authorization is not enabled." + } + ] + }, + { + "Id": "1.2.9", + "Description": "Ensure that the admission control plugin EventRateLimit is set", + "Checks": [ + "apiserver_event_rate_limit" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Limit the rate at which the API server accepts requests.", + "RationaleStatement": "Using `EventRateLimit` admission control enforces a limit on the number of events that the API Server will accept in a given time slice. A misbehaving workload could overwhelm and DoS the API Server, making it unavailable. This particularly applies to a multi-tenant cluster, where there might be a small percentage of misbehaving tenants which could have a significant impact on the performance of the cluster overall. Hence, it is recommended to limit the rate of events that the API server will accept.", + "ImpactStatement": "You need to carefully tune in limits as per your environment.", + "RemediationProcedure": "Follow the Kubernetes documentation and set the desired limits in a configuration file. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` and set the below parameters. ``` --enable-admission-plugins=...,EventRateLimit,... --admission-control-config-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--enable-admission-plugins` argument is set to a value that includes `EventRateLimit`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#eventratelimit:https://github.com/staebler/community/blob/9873b632f4d99b5d99c38c9b15fe2f8b93d0a746/contributors/design-proposals/admission_control_event_rate_limit.md", + "DefaultValue": "By default, `EventRateLimit` is not set." + } + ] + }, + { + "Id": "1.2.10", + "Description": "Ensure that the admission control plugin AlwaysAdmit is not set", + "Checks": [ + "apiserver_no_always_admit_plugin" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not allow all requests.", + "RationaleStatement": "Setting admission control plugin `AlwaysAdmit` allows all requests and do not filter any requests. The `AlwaysAdmit` admission controller was deprecated in Kubernetes v1.13. Its behavior was equivalent to turning off all admission controllers.", + "ImpactStatement": "Only requests explicitly allowed by the admissions control plugins would be served.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and either remove the `--enable-admission-plugins` parameter, or set it to a value that does not include `AlwaysAdmit`.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that if the `--enable-admission-plugins` argument is set, its value does not include `AlwaysAdmit`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwaysadmit", + "DefaultValue": "`AlwaysAdmit` is not in the list of default admission plugins." + } + ] + }, + { + "Id": "1.2.11", + "Description": "Ensure that the admission control plugin AlwaysPullImages is set", + "Checks": [ + "apiserver_always_pull_images_plugin" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Always pull images.", + "RationaleStatement": "Setting admission control policy to `AlwaysPullImages` forces every new pod to pull the required images every time. In a multi-tenant cluster users can be assured that their private images can only be used by those who have the credentials to pull them. Without this admission control policy, once an image has been pulled to a node, any pod from any user can use it simply by knowing the image’s name, without any authorization check against the image ownership. When this plug-in is enabled, images are always pulled prior to starting containers, which means valid credentials are required.", + "ImpactStatement": "Credentials would be required to pull the private images every time. Also, in trusted environments, this might increases load on network, registry, and decreases speed. This setting could impact offline or isolated clusters, which have images preloaded and do not have access to a registry to pull in-use images. This setting is not appropriate for clusters which use this configuration.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--enable-admission-plugins` parameter to include `AlwaysPullImages`. ``` --enable-admission-plugins=...,AlwaysPullImages,... ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--enable-admission-plugins` argument is set to a value that includes `AlwaysPullImages`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages", + "DefaultValue": "By default, `AlwaysPullImages` is not set." + } + ] + }, + { + "Id": "1.2.12", + "Description": "Ensure that the admission control plugin ServiceAccount is set", + "Checks": [ + "apiserver_service_account_plugin" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Automate service accounts management.", + "RationaleStatement": "When you create a pod, if you do not specify a service account, it is automatically assigned the `default` service account in the same namespace. You should create your own service account and let the API server manage its security tokens.", + "ImpactStatement": "None.", + "RemediationProcedure": "Follow the documentation and create `ServiceAccount` objects as per your environment. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and ensure that the `--disable-admission-plugins` parameter is set to a value that does not include `ServiceAccount`.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--disable-admission-plugins` argument is set to a value that does not includes `ServiceAccount`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#serviceaccount:https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/", + "DefaultValue": "By default, `ServiceAccount` is set." + } + ] + }, + { + "Id": "1.2.13", + "Description": "Ensure that the admission control plugin NamespaceLifecycle is set", + "Checks": [ + "apiserver_namespace_lifecycle_plugin" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Reject creating objects in a namespace that is undergoing termination.", + "RationaleStatement": "Setting admission control policy to `NamespaceLifecycle` ensures that objects cannot be created in non-existent namespaces, and that namespaces undergoing termination are not used for creating the new objects. This is recommended to enforce the integrity of the namespace termination process and also for the availability of the newer objects.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--disable-admission-plugins` parameter to ensure it does not include `NamespaceLifecycle`.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--disable-admission-plugins` argument is set to a value that does not include `NamespaceLifecycle`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#namespacelifecycle", + "DefaultValue": "By default, `NamespaceLifecycle` is set." + } + ] + }, + { + "Id": "1.2.14", + "Description": "Ensure that the admission control plugin NodeRestriction is set", + "Checks": [ + "apiserver_node_restriction_plugin" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Limit the `Node` and `Pod` objects that a kubelet could modify.", + "RationaleStatement": "Using the `NodeRestriction` plug-in ensures that the kubelet is restricted to the `Node` and `Pod` objects that it could modify as defined. Such kubelets will only be allowed to modify their own `Node` API object, and only modify `Pod` API objects that are bound to their node.", + "ImpactStatement": "None", + "RemediationProcedure": "Follow the Kubernetes documentation and configure `NodeRestriction` plug-in on kubelets. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the `--enable-admission-plugins` parameter to a value that includes `NodeRestriction`. ``` --enable-admission-plugins=...,NodeRestriction,... ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--enable-admission-plugins` argument is set to a value that includes `NodeRestriction`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction:https://kubernetes.io/docs/reference/access-authn-authz/node/", + "DefaultValue": "By default, `NodeRestriction` is not set." + } + ] + }, + { + "Id": "1.2.15", + "Description": "Ensure that the --profiling argument is set to false", + "Checks": [ + "apiserver_disable_profiling" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Disable profiling, if not needed.", + "RationaleStatement": "Profiling allows for the identification of specific performance bottlenecks. It generates a significant amount of program data that could potentially be exploited to uncover system and program details. If you are not experiencing any bottlenecks and do not need the profiler for troubleshooting purposes, it is recommended to turn it off to reduce the potential attack surface.", + "ImpactStatement": "Profiling information would not be available.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the below parameter. ``` --profiling=false ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--profiling` argument is set to `false`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/", + "DefaultValue": "By default, profiling is enabled." + } + ] + }, + { + "Id": "1.2.16", + "Description": "Ensure that the --audit-log-path argument is set", + "Checks": [ + "apiserver_audit_log_path_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Enable auditing on the Kubernetes API Server and set the desired audit log path.", + "RationaleStatement": "Auditing the Kubernetes API Server provides a security-relevant chronological set of records documenting the sequence of activities that have affected system by individual users, administrators or other components of the system. Even though currently, Kubernetes provides only basic audit capabilities, it should be enabled. You can enable it by setting an appropriate audit log path.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--audit-log-path` parameter to a suitable path and file where you would like audit logs to be written, for example: ``` --audit-log-path=/var/log/apiserver/audit.log ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--audit-log-path` argument is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/:https://github.com/kubernetes/enhancements/issues/22", + "DefaultValue": "By default, auditing is not enabled." + } + ] + }, + { + "Id": "1.2.17", + "Description": "Ensure that the --audit-log-maxage argument is set to 30 or as appropriate", + "Checks": [ + "apiserver_audit_log_maxage_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Retain the logs for at least 30 days or as appropriate.", + "RationaleStatement": "Retaining logs for at least 30 days ensures that you can go back in time and investigate or correlate any events. Set your audit log retention period to 30 days or as per your business requirements.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--audit-log-maxage` parameter to 30 or as an appropriate number of days: ``` --audit-log-maxage=30 ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--audit-log-maxage` argument is set to `30` or as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/:https://github.com/kubernetes/enhancements/issues/22", + "DefaultValue": "By default, auditing is not enabled." + } + ] + }, + { + "Id": "1.2.18", + "Description": "Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate", + "Checks": [ + "apiserver_audit_log_maxbackup_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Retain 10 or an appropriate number of old log files.", + "RationaleStatement": "Kubernetes automatically rotates the log files. Retaining old log files ensures that you would have sufficient log data available for carrying out any investigation or correlation. For example, if you have set file size of 100 MB and the number of old log files to keep as 10, you would approximate have 1 GB of log data that you could potentially use for your analysis.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--audit-log-maxbackup` parameter to 10 or to an appropriate value. ``` --audit-log-maxbackup=10 ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--audit-log-maxbackup` argument is set to `10` or as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/:https://github.com/kubernetes/enhancements/issues/22", + "DefaultValue": "By default, auditing is not enabled." + } + ] + }, + { + "Id": "1.2.19", + "Description": "Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate", + "Checks": [ + "apiserver_audit_log_maxsize_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Rotate log files on reaching 100 MB or as appropriate.", + "RationaleStatement": "Kubernetes automatically rotates the log files. Retaining old log files ensures that you would have sufficient log data available for carrying out any investigation or correlation. If you have set file size of 100 MB and the number of old log files to keep as 10, you would approximate have 1 GB of log data that you could potentially use for your analysis.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--audit-log-maxsize` parameter to an appropriate size in MB. For example, to set it as 100 MB: ``` --audit-log-maxsize=100 ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--audit-log-maxsize` argument is set to `100` or as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/:https://github.com/kubernetes/enhancements/issues/22", + "DefaultValue": "By default, auditing is not enabled." + } + ] + }, + { + "Id": "1.2.20", + "Description": "Ensure that the --request-timeout argument is set as appropriate", + "Checks": [ + "apiserver_request_timeout_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Set global request timeout for API server requests as appropriate.", + "RationaleStatement": "Setting global request timeout allows extending the API server request timeout limit to a duration appropriate to the user's connection speed. By default, it is set to 60 seconds which might be problematic on slower connections making cluster resources inaccessible once the data volume for requests exceeds what can be transmitted in 60 seconds. But, setting this timeout limit to be too large can exhaust the API server resources making it prone to Denial-of-Service attack. Hence, it is recommended to set this limit as appropriate and change the default limit of 60 seconds only if needed.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` and set the below parameter as appropriate and if needed. For example, ``` --request-timeout=300s ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--request-timeout` argument is either not set or set to an appropriate value.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kubernetes/kubernetes/pull/51415", + "DefaultValue": "By default, `--request-timeout` is set to 60 seconds." + } + ] + }, + { + "Id": "1.2.21", + "Description": "Ensure that the --service-account-lookup argument is set to true", + "Checks": [ + "apiserver_service_account_lookup_true" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Validate service account before validating token.", + "RationaleStatement": "If `--service-account-lookup` is not enabled, the apiserver only verifies that the authentication token is valid, and does not validate that the service account token mentioned in the request is actually present in etcd. This allows using a service account token even after the corresponding service account is deleted. This is an example of time of check to time of use security issue.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the below parameter. ``` --service-account-lookup=true ``` Alternatively, you can delete the `--service-account-lookup` parameter from this file so that the default takes effect.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that if the `--service-account-lookup` argument exists it is set to `true`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kubernetes/kubernetes/issues/24167:https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use", + "DefaultValue": "By default, `--service-account-lookup` argument is set to `true`." + } + ] + }, + { + "Id": "1.2.22", + "Description": "Ensure that the --service-account-key-file argument is set as appropriate", + "Checks": [ + "apiserver_service_account_key_file_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Explicitly set a service account public key file for service accounts on the apiserver.", + "RationaleStatement": "By default, if no `--service-account-key-file` is specified to the apiserver, it uses the private key from the TLS serving certificate to verify service account tokens. To ensure that the keys for service account tokens could be rotated as needed, a separate public/private key pair should be used for signing service account tokens. Hence, the public key should be specified to the apiserver with `--service-account-key-file`.", + "ImpactStatement": "The corresponding private key must be provided to the controller manager. You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", + "RemediationProcedure": "Edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the Control Plane node and set the `--service-account-key-file` parameter to the public key file for service accounts: ``` --service-account-key-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--service-account-key-file` argument exists and is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kubernetes/kubernetes/issues/24167", + "DefaultValue": "By default, `--service-account-key-file` argument is not set." + } + ] + }, + { + "Id": "1.2.23", + "Description": "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate", + "Checks": [ + "apiserver_etcd_tls_config" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "etcd should be configured to make use of TLS encryption for client connections.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be protected by client authentication. This requires the API server to identify itself to the etcd server using a client certificate and key.", + "ImpactStatement": "TLS and client certificate authentication must be configured for etcd.", + "RemediationProcedure": "Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the etcd certificate and key file parameters. ``` --etcd-certfile= --etcd-keyfile= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--etcd-certfile` and `--etcd-keyfile` arguments exist and they are set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/", + "DefaultValue": "By default, `--etcd-certfile` and `--etcd-keyfile` arguments are not set" + } + ] + }, + { + "Id": "1.2.24", + "Description": "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate", + "Checks": [ + "apiserver_tls_config" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Setup TLS connection on the API server.", + "RationaleStatement": "API server communication contains sensitive parameters that should remain encrypted in transit. Configure the API server to serve only HTTPS traffic.", + "ImpactStatement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", + "RemediationProcedure": "Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the TLS certificate and private key file parameters. ``` --tls-cert-file= --tls-private-key-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--tls-cert-file` and `--tls-private-key-file` arguments exist and they are set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kelseyhightower/docker-kubernetes-tls-guide", + "DefaultValue": "By default, `--tls-cert-file` and `--tls-private-key-file` are presented and created for use." + } + ] + }, + { + "Id": "1.2.25", + "Description": "Ensure that the --client-ca-file argument is set as appropriate", + "Checks": [ + "apiserver_client_ca_file_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Setup TLS connection on the API server.", + "RationaleStatement": "API server communication contains sensitive parameters that should remain encrypted in transit. Configure the API server to serve only HTTPS traffic. If `--client-ca-file` argument is set, any request presenting a client certificate signed by one of the authorities in the `client-ca-file` is authenticated with an identity corresponding to the CommonName of the client certificate.", + "ImpactStatement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", + "RemediationProcedure": "Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the client certificate authority file. ``` --client-ca-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--client-ca-file` argument exists and it is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kelseyhightower/docker-kubernetes-tls-guide", + "DefaultValue": "By default, `--client-ca-file` argument is not set." + } + ] + }, + { + "Id": "1.2.26", + "Description": "Ensure that the --etcd-cafile argument is set as appropriate", + "Checks": [ + "apiserver_etcd_cafile_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "etcd should be configured to make use of TLS encryption for client connections.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be protected by client authentication. This requires the API server to identify itself to the etcd server using a SSL Certificate Authority file.", + "ImpactStatement": "TLS and client certificate authentication must be configured for etcd.", + "RemediationProcedure": "Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the etcd certificate authority file parameter. ``` --etcd-cafile= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--etcd-cafile` argument exists and it is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/", + "DefaultValue": "By default, `--etcd-cafile` is not set." + } + ] + }, + { + "Id": "1.2.27", + "Description": "Ensure that the --encryption-provider-config argument is set as appropriate", + "Checks": [ + "apiserver_encryption_provider_config_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Encrypt etcd key-value store.", + "RationaleStatement": "etcd is a highly available key-value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be encrypted at rest to avoid any disclosures.", + "ImpactStatement": "None", + "RemediationProcedure": "Follow the Kubernetes documentation and configure a `EncryptionConfig` file. Then, edit the API server pod specification file `/etc/kubernetes/manifests/kube-apiserver.yaml` on the master node and set the `--encryption-provider-config` parameter to the path of that file: ``` --encryption-provider-config= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--encryption-provider-config` argument is set to a `EncryptionConfig` file. Additionally, ensure that the `EncryptionConfig` file has all the desired `resources` covered especially any secrets.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/:https://acotten.com/post/kube17-security:https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kubernetes/enhancements/issues/92", + "DefaultValue": "By default, `--encryption-provider-config` is not set." + } + ] + }, + { + "Id": "1.2.28", + "Description": "Ensure that encryption providers are appropriately configured", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Where `etcd` encryption is used, appropriate providers should be configured.", + "RationaleStatement": "Where `etcd` encryption is used, it is important to ensure that the appropriate set of encryption providers is used. Currently, the `aescbc`, `kms`, and `secretbox` are likely to be appropriate options.", + "ImpactStatement": "None", + "RemediationProcedure": "Follow the Kubernetes documentation and configure a `EncryptionConfig` file. In this file, choose `aescbc`, `kms`, or `secretbox` as the encryption provider.", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Get the `EncryptionConfig` file set for `--encryption-provider-config` argument. Verify that `aescbc`, `kms`, or `secretbox` is set as the encryption provider for all the desired `resources`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/:https://acotten.com/post/kube17-security:https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/kubernetes/enhancements/issues/92:https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#providers", + "DefaultValue": "By default, no encryption provider is set." + } + ] + }, + { + "Id": "1.2.29", + "Description": "Ensure that the API Server only makes use of Strong Cryptographic Ciphers", + "Checks": [ + "apiserver_strong_ciphers_only" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the API server is configured to only use strong cryptographic ciphers.", + "RationaleStatement": "TLS ciphers have had a number of known vulnerabilities and weaknesses, which can reduce the protection provided by them. By default Kubernetes supports a number of TLS cipher suites including some that have security concerns, weakening the protection provided.", + "ImpactStatement": "API server clients that cannot support modern cryptographic ciphers will not be able to make connections to the API server.", + "RemediationProcedure": "Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the Control Plane node and set the below parameter. ``` --tls-cipher-suites=TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256. ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the `--tls-cipher-suites` argument is set as outlined in the remediation procedure below.", + "AdditionalInformation": "Insecure values: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_RC4_128_SHA.", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/:https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices#23-use-secure-cipher-suites", + "DefaultValue": "By default the Kubernetes API server supports a wide range of TLS ciphers" + } + ] + }, + { + "Id": "1.2.30", + "Description": "Ensure that the --service-account-extend-token-expiration parameter is set to false", + "Checks": [], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.2 API Server", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "By default Kubernetes extends service account token lifetimes to one year to aid in transition from the legacy token settings.", + "RationaleStatement": "This default setting is not ideal for security as it ignores other settings related to maximum token lifetime and means that a lost or stolen credential could be valid for an extended period of time.", + "ImpactStatement": "Disabling this setting means that the service account token expiry set in the cluster will be enforced, and service account tokens will expire at the end of that time frame.", + "RemediationProcedure": "Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the Control Plane node and set the --service-account-extend-token-expiration parameter to false. ``` --service-account-extend-token-expiration=false ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-apiserver ``` Verify that the --service-account-extend-token-expiration argument is set to false.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/", + "DefaultValue": "By default, this parameter is set to true" + } + ] + }, + { + "Id": "1.3.1", + "Description": "Ensure that the --terminated-pod-gc-threshold argument is set as appropriate", + "Checks": [ + "controllermanager_garbage_collection" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Activate garbage collector on pod termination, as appropriate.", + "RationaleStatement": "Garbage collection is important to ensure sufficient resource availability and avoiding degraded performance and availability. In the worst case, the system might crash or just be unusable for a long period of time. The current setting for garbage collection is 12,500 terminated pods which might be too high for your system to sustain. Based on your system resources and tests, choose an appropriate threshold value to activate garbage collection.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and set the `--terminated-pod-gc-threshold` to an appropriate threshold, for example: ``` --terminated-pod-gc-threshold=10 ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--terminated-pod-gc-threshold` argument is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/:https://github.com/kubernetes/kubernetes/issues/28484", + "DefaultValue": "By default, `--terminated-pod-gc-threshold` is set to `12500`." + } + ] + }, + { + "Id": "1.3.2", + "Description": "Ensure that the --profiling argument is set to false", + "Checks": [ + "controllermanager_disable_profiling" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Disable profiling, if not needed.", + "RationaleStatement": "Profiling allows for the identification of specific performance bottlenecks. It generates a significant amount of program data that could potentially be exploited to uncover system and program details. If you are not experiencing any bottlenecks and do not need the profiler for troubleshooting purposes, it is recommended to turn it off to reduce the potential attack surface.", + "ImpactStatement": "Profiling information would not be available.", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and set the below parameter. ``` --profiling=false ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--profiling` argument is set to `false`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/:https://github.com/kubernetes/community/blob/master/contributors/devel/profiling.md", + "DefaultValue": "By default, profiling is enabled." + } + ] + }, + { + "Id": "1.3.3", + "Description": "Ensure that the --use-service-account-credentials argument is set to true", + "Checks": [ + "controllermanager_service_account_credentials" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Use individual service account credentials for each controller.", + "RationaleStatement": "The controller manager creates a service account per controller in the `kube-system` namespace, generates a credential for it, and builds a dedicated API client with that service account credential for each controller loop to use. Setting the `--use-service-account-credentials` to `true` runs each control loop within the controller manager using a separate service account credential. When used in combination with RBAC, this ensures that the control loops run with the minimum permissions required to perform their intended tasks.", + "ImpactStatement": "Whatever authorizer is configured for the cluster, it must grant sufficient permissions to the service accounts to perform their intended tasks. When using the RBAC authorizer, those roles are created and bound to the appropriate service accounts in the `kube-system` namespace automatically with default roles and rolebindings that are auto-reconciled on startup. If using other authorization methods (ABAC, Webhook, etc), the cluster deployer is responsible for granting appropriate permissions to the service accounts (the required permissions can be seen by inspecting the `controller-roles.yaml` and `controller-role-bindings.yaml` files for the RBAC roles.", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node to set the below parameter. ``` --use-service-account-credentials=true ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--use-service-account-credentials` argument is set to `true`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/:https://kubernetes.io/docs/admin/service-accounts-admin/:https://github.com/kubernetes/kubernetes/blob/release-1.6/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml:https://github.com/kubernetes/kubernetes/blob/release-1.6/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-role-bindings.yaml:https://kubernetes.io/docs/admin/authorization/rbac/#controller-roles", + "DefaultValue": "By default, `--use-service-account-credentials` is set to false." + } + ] + }, + { + "Id": "1.3.4", + "Description": "Ensure that the --service-account-private-key-file argument is set as appropriate", + "Checks": [ + "controllermanager_service_account_private_key_file" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Explicitly set a service account private key file for service accounts on the controller manager.", + "RationaleStatement": "To ensure that keys for service account tokens can be rotated as needed, a separate public/private key pair should be used for signing service account tokens. The private key should be specified to the controller manager with `--service-account-private-key-file` as appropriate.", + "ImpactStatement": "You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and set the `--service-account-private-key-file` parameter to the private key file for service accounts. ``` --service-account-private-key-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--service-account-private-key-file` argument is set as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/", + "DefaultValue": "By default, `--service-account-private-key-file` it not set." + } + ] + }, + { + "Id": "1.3.5", + "Description": "Ensure that the --root-ca-file argument is set as appropriate", + "Checks": [ + "controllermanager_root_ca_file_set" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Allow pods to verify the API server's serving certificate before establishing connections.", + "RationaleStatement": "Processes running within pods that need to contact the API server must verify the API server's serving certificate. Failing to do so could be a subject to man-in-the-middle attacks. Providing the root certificate for the API server's serving certificate to the controller manager with the `--root-ca-file` argument allows the controller manager to inject the trusted bundle into pods so that they can verify TLS connections to the API server.", + "ImpactStatement": "You need to setup and maintain root certificate authority file.", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and set the `--root-ca-file` parameter to the certificate bundle file`. ``` --root-ca-file= ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--root-ca-file` argument exists and is set to a certificate bundle file containing the root certificate for the API server's serving certificate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-controller-manager/:https://github.com/kubernetes/kubernetes/issues/11000", + "DefaultValue": "By default, `--root-ca-file` is not set." + } + ] + }, + { + "Id": "1.3.6", + "Description": "Ensure that the RotateKubeletServerCertificate argument is set to true", + "Checks": [ + "controllermanager_rotate_kubelet_server_cert" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Enable kubelet server certificate rotation on controller-manager.", + "RationaleStatement": "`RotateKubeletServerCertificate` causes the kubelet to both request a serving certificate after bootstrapping its client credentials and rotate the certificate as its existing credentials expire. This automated periodic rotation ensures that the there are no downtimes due to expired certificates and thus addressing availability in the CIA security triad. Note: This recommendation only applies if you let kubelets get their certificates from the API server. In case your kubelet certificates come from an outside authority/tool (e.g. Vault) then you need to take care of rotation yourself.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and set the `--feature-gates` parameter to include `RotateKubeletServerCertificate=true`. ``` --feature-gates=RotateKubeletServerCertificate=true ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that `RotateKubeletServerCertificate` argument exists and is set to `true`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet-tls-bootstrapping/#approval-controller:https://github.com/kubernetes/features/issues/267:https://github.com/kubernetes/kubernetes/pull/45059:https://kubernetes.io/docs/admin/kube-controller-manager/", + "DefaultValue": "By default, `RotateKubeletServerCertificate` is set to true this recommendation verifies that it has not been disabled." + } + ] + }, + { + "Id": "1.3.7", + "Description": "Ensure that the --bind-address argument is set to 127.0.0.1", + "Checks": [ + "controllermanager_bind_address" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.3 Controller Manager", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not bind the Controller Manager service to non-loopback insecure addresses.", + "RationaleStatement": "The Controller Manager API service which runs on port 10252/TCP by default is used for health and metrics information and is available without authentication or encryption. As such it should only be bound to a localhost interface, to minimize the cluster's attack surface", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the Controller Manager pod specification file `/etc/kubernetes/manifests/kube-controller-manager.yaml` on the Control Plane node and ensure the correct value for the `--bind-address` parameter", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-controller-manager ``` Verify that the `--bind-address` argument is set to 127.0.0.1", + "AdditionalInformation": "Although the current Kubernetes documentation site says that `--address` is deprecated in favour of `--bind-address` Kubeadm 1.11 still makes use of `--address`", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/", + "DefaultValue": "By default, the `--bind-address` parameter is set to 0.0.0.0" + } + ] + }, + { + "Id": "1.4.1", + "Description": "Ensure that the --profiling argument is set to false", + "Checks": [ + "scheduler_profiling" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.4 Scheduler", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Disable profiling, if not needed.", + "RationaleStatement": "Profiling allows for the identification of specific performance bottlenecks. It generates a significant amount of program data that could potentially be exploited to uncover system and program details. If you are not experiencing any bottlenecks and do not need the profiler for troubleshooting purposes, it is recommended to turn it off to reduce the potential attack surface.", + "ImpactStatement": "Profiling information would not be available.", + "RemediationProcedure": "Edit the Scheduler pod specification file `/etc/kubernetes/manifests/kube-scheduler.yaml` file on the Control Plane node and set the below parameter. ``` --profiling=false ```", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-scheduler ``` Verify that the `--profiling` argument is set to `false`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-scheduler/:https://github.com/kubernetes/community/blob/master/contributors/devel/profiling.md", + "DefaultValue": "By default, profiling is enabled." + } + ] + }, + { + "Id": "1.4.2", + "Description": "Ensure that the --bind-address argument is set to 127.0.0.1", + "Checks": [ + "scheduler_bind_address" + ], + "Attributes": [ + { + "Section": "1 Control Plane Components", + "SubSection": "1.4 Scheduler", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not bind the scheduler service to non-loopback insecure addresses.", + "RationaleStatement": "The Scheduler API service which runs on port 10251/TCP by default is used for health and metrics information and is available without authentication or encryption. As such it should only be bound to a localhost interface, to minimize the cluster's attack surface", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the Scheduler pod specification file `/etc/kubernetes/manifests/kube-scheduler.yaml` on the Control Plane node and ensure the correct value for the `--bind-address` parameter", + "AuditProcedure": "Run the following command on the Control Plane node: ``` ps -ef | grep kube-scheduler ``` Verify that the `--bind-address` argument is set to 127.0.0.1", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/", + "DefaultValue": "By default, the `--bind-address` parameter is set to 0.0.0.0" + } + ] + }, + { + "Id": "2.1", + "Description": "Ensure that the --cert-file and --key-file arguments are set as appropriate", + "Checks": [ + "etcd_tls_encryption" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Configure TLS encryption for the etcd service.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be encrypted in transit.", + "ImpactStatement": "Client connections only over TLS would be served.", + "RemediationProcedure": "Follow the etcd service documentation and configure TLS encryption. Then, edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameters. ``` --cert-file= --key-file= ```", + "AuditProcedure": "Run the following command on the etcd server node ``` ps -ef | grep etcd ``` Verify that the `--cert-file` and the `--key-file` arguments are set as appropriate.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, TLS encryption is not set." + } + ] + }, + { + "Id": "2.2", + "Description": "Ensure that the --cert-file and --key-file arguments are set as appropriate", + "Checks": [ + "etcd_tls_encryption" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Configure TLS encryption for the etcd service.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be encrypted in transit.", + "ImpactStatement": "Client connections only over TLS would be served.", + "RemediationProcedure": "Follow the etcd service documentation and configure TLS encryption. Then, edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameters. ``` --cert-file= --key-file= ```", + "AuditProcedure": "Run the following command on the etcd server node ``` ps -ef | grep etcd ``` Verify that the `--cert-file` and the `--key-file` arguments are set as appropriate.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "By default, TLS encryption is not set." + } + ] + }, + { + "Id": "2.3", + "Description": "Ensure that the --client-cert-auth argument is set to true", + "Checks": [ + "etcd_client_cert_auth" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Enable client authentication on etcd service.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should not be available to unauthenticated clients. You should enable the client authentication via valid certificates to secure the access to the etcd service.", + "ImpactStatement": "All clients attempting to access the etcd server will require a valid client certificate.", + "RemediationProcedure": "Edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameter. ``` --client-cert-auth=true ```", + "AuditProcedure": "Run the following command on the etcd server node: ``` ps -ef | grep etcd ``` Verify that the `--client-cert-auth` argument is set to `true`.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/:https://coreos.com/etcd/docs/latest/op-guide/configuration.html#client-cert-auth", + "DefaultValue": "By default, the etcd service can be queried by unauthenticated clients." + } + ] + }, + { + "Id": "2.4", + "Description": "Ensure that the --auto-tls argument is not set to true", + "Checks": [ + "etcd_no_auto_tls" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not use self-signed certificates for TLS.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should not be available to unauthenticated clients. You should enable the client authentication via valid certificates to secure the access to the etcd service.", + "ImpactStatement": "Clients will not be able to use self-signed certificates for TLS.", + "RemediationProcedure": "Edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and either remove the `--auto-tls` parameter or set it to `false`. ``` --auto-tls=false ```", + "AuditProcedure": "Run the following command on the etcd server node: ``` ps -ef | grep etcd ``` Verify that if the `--auto-tls` argument exists, it is not set to `true`.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/:https://coreos.com/etcd/docs/latest/op-guide/configuration.html#auto-tls", + "DefaultValue": "By default, `--auto-tls` is set to `false`." + } + ] + }, + { + "Id": "2.5", + "Description": "Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate", + "Checks": [ + "etcd_peer_tls_config" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "etcd should be configured to make use of TLS encryption for peer connections.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be encrypted in transit and also amongst peers in the etcd clusters.", + "ImpactStatement": "etcd cluster peers would need to set up TLS for their communication.", + "RemediationProcedure": "Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. Then, edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameters. ``` --peer-client-file= --peer-key-file= ```", + "AuditProcedure": "Run the following command on the etcd server node: ``` ps -ef | grep etcd ``` Verify that the `--peer-cert-file` and `--peer-key-file` arguments are set as appropriate. **Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/", + "DefaultValue": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable. By default, peer communication over TLS is not configured." + } + ] + }, + { + "Id": "2.6", + "Description": "Ensure that the --peer-client-cert-auth argument is set to true", + "Checks": [ + "etcd_peer_client_cert_auth" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "etcd should be configured for peer authentication.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be accessible only by authenticated etcd peers in the etcd cluster.", + "ImpactStatement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", + "RemediationProcedure": "Edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameter. ``` --peer-client-cert-auth=true ```", + "AuditProcedure": "Run the following command on the etcd server node: ``` ps -ef | grep etcd ``` Verify that the `--peer-client-cert-auth` argument is set to `true`. **Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/:https://coreos.com/etcd/docs/latest/op-guide/configuration.html#peer-client-cert-auth", + "DefaultValue": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable. By default, `--peer-client-cert-auth` argument is set to `false`." + } + ] + }, + { + "Id": "2.7", + "Description": "Ensure that the --peer-auto-tls argument is not set to true", + "Checks": [ + "etcd_no_peer_auto_tls" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Do not use automatically generated self-signed certificates for TLS connections between peers.", + "RationaleStatement": "etcd is a highly-available key value store used by Kubernetes deployments for persistent storage of all of its REST API objects. These objects are sensitive in nature and should be accessible only by authenticated etcd peers in the etcd cluster. Hence, do not use self-signed certificates for authentication.", + "ImpactStatement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", + "RemediationProcedure": "Edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and either remove the `--peer-auto-tls` parameter or set it to `false`. ``` --peer-auto-tls=false ```", + "AuditProcedure": "Run the following command on the etcd server node: ``` ps -ef | grep etcd ``` Verify that if the `--peer-auto-tls` argument exists, it is not set to `true`. **Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html:https://kubernetes.io/docs/admin/etcd/:https://coreos.com/etcd/docs/latest/op-guide/configuration.html#peer-auto-tls", + "DefaultValue": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable. By default, `--peer-auto-tls` argument is set to `false`." + } + ] + }, + { + "Id": "2.8", + "Description": "Ensure that a unique Certificate Authority is used for etcd", + "Checks": [ + "etcd_unique_ca" + ], + "Attributes": [ + { + "Section": "2 etcd", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Use a different certificate authority for etcd from the one used for Kubernetes.", + "RationaleStatement": "etcd is a highly available key-value store used by Kubernetes deployments for persistent storage of all of its REST API objects. Its access should be restricted to specifically designated clients and peers only. Authentication to etcd is based on whether the certificate presented was issued by a trusted certificate authority. There is no checking of certificate attributes such as common name or subject alternative name. As such, if any attackers were able to gain access to any certificate issued by the trusted certificate authority, they would be able to gain full access to the etcd database.", + "ImpactStatement": "Additional management of the certificates and keys for the dedicated certificate authority will be required.", + "RemediationProcedure": "Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. Then, edit the etcd pod specification file `/etc/kubernetes/manifests/etcd.yaml` on the master node and set the below parameter. ``` --trusted-ca-file= ```", + "AuditProcedure": "Review the CA used by the etcd environment and ensure that it does not match the CA certificate file used for the management of the overall Kubernetes cluster. Run the following command on the master node: ``` ps -ef | grep etcd ``` Note the file referenced by the `--trusted-ca-file` argument. Run the following command on the master node: ``` ps -ef | grep apiserver ``` Verify that the file referenced by the `--client-ca-file` for apiserver is different from the `--trusted-ca-file` used by etcd.", + "AdditionalInformation": "", + "References": "https://coreos.com/etcd/docs/latest/op-guide/security.html", + "DefaultValue": "By default, no etcd certificate is created and used." + } + ] + }, + { + "Id": "3.1.1", + "Description": "Client certificate authentication should not be used for users", + "Checks": [], + "Attributes": [ + { + "Section": "3 Control Plane Configuration", + "SubSection": "3.1 Authentication and Authorization", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes provides the option to use client certificates for user authentication. However as there is no way to revoke these certificates when a user leaves an organization or loses their credential, they are not suitable for this purpose. It is not possible to fully disable client certificate use within a cluster as it is used for component to component authentication.", + "RationaleStatement": "With any authentication mechanism the ability to revoke credentials if they are compromised or no longer required, is a key control. Kubernetes client certificate authentication does not allow for this due to a lack of support for certificate revocation.", + "ImpactStatement": "External mechanisms for authentication generally require additional software to be deployed.", + "RemediationProcedure": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of client certificates.", + "AuditProcedure": "Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication.", + "AdditionalInformation": "The lack of certificate revocation was flagged up as a high risk issue in the recent Kubernetes security audit. Without this feature, client certificate authentication is not suitable for end users.", + "References": "", + "DefaultValue": "Client certificate authentication is enabled by default." + } + ] + }, + { + "Id": "3.1.2", + "Description": "Service account token authentication should not be used for users", + "Checks": [], + "Attributes": [ + { + "Section": "3 Control Plane Configuration", + "SubSection": "3.1 Authentication and Authorization", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes provides service account tokens which are intended for use by workloads running in the Kubernetes cluster, for authentication to the API server. These tokens are not designed for use by end-users and do not provide for features such as revocation or expiry, making them insecure. A newer version of the feature (Bound service account token volumes) does introduce expiry but still does not allow for specific revocation.", + "RationaleStatement": "With any authentication mechanism the ability to revoke credentials if they are compromised or no longer required, is a key control. Service account token authentication does not allow for this due to the use of JWT tokens as an underlying technology.", + "ImpactStatement": "External mechanisms for authentication generally require additional software to be deployed.", + "RemediationProcedure": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of service account tokens.", + "AuditProcedure": "Review user access to the cluster and ensure that users are not making use of service account token authentication.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "Service account token authentication is enabled by default." + } + ] + }, + { + "Id": "3.1.3", + "Description": "Bootstrap token authentication should not be used for users", + "Checks": [], + "Attributes": [ + { + "Section": "3 Control Plane Configuration", + "SubSection": "3.1 Authentication and Authorization", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes provides bootstrap tokens which are intended for use by new nodes joining the cluster These tokens are not designed for use by end-users they are specifically designed for the purpose of bootstrapping new nodes and not for general authentication", + "RationaleStatement": "Bootstrap tokens are not intended for use as a general authentication mechanism and impose constraints on user and group naming that do not facilitate good RBAC design. They also cannot be used with MFA resulting in a weak authentication mechanism being available.", + "ImpactStatement": "External mechanisms for authentication generally require additional software to be deployed.", + "RemediationProcedure": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of bootstrap tokens.", + "AuditProcedure": "Review user access to the cluster and ensure that users are not making use of bootstrap token authentication.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "Bootstrap token authentication is not enabled by default and requires an API server parameter to be set." + } + ] + }, + { + "Id": "3.2.1", + "Description": "Ensure that a minimal audit policy is created", + "Checks": [], + "Attributes": [ + { + "Section": "3 Control Plane Configuration", + "SubSection": "3.2 Logging", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes can audit the details of requests made to the API server. The `--audit-policy-file` flag must be set for this logging to be enabled.", + "RationaleStatement": "Logging is an important detective control for all systems, to detect potential unauthorised access.", + "ImpactStatement": "Audit logs will be created on the master nodes, which will consume disk space. Care should be taken to avoid generating too large volumes of log information as this could impact the available of the cluster nodes.", + "RemediationProcedure": "Create an audit policy file for your cluster.", + "AuditProcedure": "Run the following command on one of the cluster master nodes: ``` ps -ef | grep kube-apiserver ``` Verify that the `--audit-policy-file` is set. Review the contents of the file specified and ensure that it contains a valid audit policy.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/debug-application-cluster/audit/", + "DefaultValue": "Unless the `--audit-policy-file` flag is specified, no auditing will be carried out." + } + ] + }, + { + "Id": "3.2.2", + "Description": "Ensure that the audit policy covers key security concerns", + "Checks": [], + "Attributes": [ + { + "Section": "3 Control Plane Configuration", + "SubSection": "3.2 Logging", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the audit policy created for the cluster covers key security concerns.", + "RationaleStatement": "Security audit logs should cover access and modification of key resources in the cluster, to enable them to form an effective part of a security environment.", + "ImpactStatement": "Increasing audit logging will consume resources on the nodes or other log destination.", + "RemediationProcedure": "Consider modification of the audit policy in use on the cluster to include these items, at a minimum.", + "AuditProcedure": "Review the audit policy provided for the cluster and ensure that it covers at least the following areas :- - Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data. - Modification of `pod` and `deployment` objects. - Use of `pods/exec`, `pods/portforward`, `pods/proxy` and `services/proxy`. For most requests, minimally logging at the Metadata level is recommended (the most basic level of logging).", + "AdditionalInformation": "", + "References": "https://github.com/k8scop/k8s-security-dashboard/blob/master/configs/kubernetes/adv-audit.yaml:https://kubernetes.io/docs/tasks/debug-application-cluster/audit/#audit-policy:https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh#L735", + "DefaultValue": "By default Kubernetes clusters do not log audit information." + } + ] + }, + { + "Id": "4.1.1", + "Description": "Ensure that the kubelet service file permissions are set to 600 or more restrictive", + "Checks": [ + "kubelet_service_file_permissions" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `kubelet` service file has permissions of `600` or more restrictive.", + "RationaleStatement": "The `kubelet` service file controls various parameters that set the behavior of the `kubelet` service in the worker node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chmod 600 /etc/systemd/system/kubelet.service.d/kubeadm.conf ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet service config file. Please set $kubelet_service_config= based on the file location on your system for example: ``` export kubelet_service_config=/etc/systemd/system/kubelet.service.d/kubeadm.conf ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %a /etc/systemd/system/kubelet.service.d/10-kubeadm.conf ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/#44-joining-your-nodes:https://kubernetes.io/docs/admin/kubeadm/#kubelet-drop-in", + "DefaultValue": "By default, the `kubelet` service file has permissions of `640`." + } + ] + }, + { + "Id": "4.1.2", + "Description": "Ensure that the kubelet service file ownership is set to root:root", + "Checks": [ + "kubelet_service_file_ownership_root" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `kubelet` service file ownership is set to `root:root`.", + "RationaleStatement": "The `kubelet` service file controls various parameters that set the behavior of the `kubelet` service in the worker node. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chown root:root /etc/systemd/system/kubelet.service.d/kubeadm.conf ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet service config file. Please set $kubelet_service_config= based on the file location on your system for example: ``` export kubelet_service_config=/etc/systemd/system/kubelet.service.d/kubeadm.conf ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %U:%G /etc/systemd/system/kubelet.service.d/10-kubeadm.conf ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/#44-joining-your-nodes:https://kubernetes.io/docs/admin/kubeadm/#kubelet-drop-in", + "DefaultValue": "By default, `kubelet` service file ownership is set to `root:root`." + } + ] + }, + { + "Id": "4.1.3", + "Description": "If proxy kubeconfig file exists ensure permissions are set to 600 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "If `kube-proxy` is running, and if it is using a file-based kubeconfig file, ensure that the proxy kubeconfig file has permissions of `600` or more restrictive.", + "RationaleStatement": "The `kube-proxy` kubeconfig file controls various parameters of the `kube-proxy` service in the worker node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system. It is possible to run `kube-proxy` with the kubeconfig parameters configured as a Kubernetes ConfigMap instead of a file. In this case, there is no proxy kubeconfig file.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chmod 600 ```", + "AuditProcedure": "Find the kubeconfig file being used by `kube-proxy` by running the following command: ``` ps -ef | grep kube-proxy ``` If `kube-proxy` is running, get the kubeconfig file location from the `--kubeconfig` parameter. To perform the audit: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %a ``` Verify that a file is specified and it exists with permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-proxy/", + "DefaultValue": "By default, proxy file has permissions of `640`." + } + ] + }, + { + "Id": "4.1.4", + "Description": "If proxy kubeconfig file exists ensure ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "If `kube-proxy` is running, ensure that the file ownership of its kubeconfig file is set to `root:root`.", + "RationaleStatement": "The kubeconfig file for `kube-proxy` controls various parameters for the `kube-proxy` service in the worker node. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chown root:root ```", + "AuditProcedure": "Find the kubeconfig file being used by `kube-proxy` by running the following command: ``` ps -ef | grep kube-proxy ``` If `kube-proxy` is running, get the kubeconfig file location from the `--kubeconfig` parameter. To perform the audit: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %U:%G ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kube-proxy/", + "DefaultValue": "By default, `proxy` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "4.1.5", + "Description": "Ensure that the --kubeconfig kubelet.conf file permissions are set to 600 or more restrictive", + "Checks": [ + "kubelet_conf_file_permissions" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `kubelet.conf` file has permissions of `600` or more restrictive.", + "RationaleStatement": "The `kubelet.conf` file is the kubeconfig file for the node, and controls various parameters that set the behavior and identity of the worker node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chmod 600 /etc/kubernetes/kubelet.conf ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet config file. Please set $kubelet_config= based on the file location on your system for example: ``` export kubelet_config=/etc/kubernetes/kubelet.conf ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %a /etc/kubernetes/kubelet.conf ``` Verify that the ownership is set to `root:root`.Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/", + "DefaultValue": "By default, `kubelet.conf` file has permissions of `600`." + } + ] + }, + { + "Id": "4.1.6", + "Description": "Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root", + "Checks": [ + "kubelet_conf_file_ownership" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that the `kubelet.conf` file ownership is set to `root:root`.", + "RationaleStatement": "The `kubelet.conf` file is the kubeconfig file for the node, and controls various parameters that set the behavior and identity of the worker node. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the below command (based on the file location on your system) on the each worker node. For example, ``` chown root:root /etc/kubernetes/kubelet.conf ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet config file. Please set $kubelet_config= based on the file location on your system for example: ``` export kubelet_config=/etc/kubernetes/kubelet.conf ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %U:%G /etc/kubernetes/kubelet.conf ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/", + "DefaultValue": "By default, `kubelet.conf` file ownership is set to `root:root`." + } + ] + }, + { + "Id": "4.1.7", + "Description": "Ensure that the certificate authorities file permissions are set to 644 or more restrictive", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the certificate authorities file has permissions of `644` or more restrictive.", + "RationaleStatement": "The certificate authorities file controls the authorities used to validate API requests. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the following command to modify the file permissions of the `--client-ca-file` ``` chmod 644 ```", + "AuditProcedure": "Run the following command: ``` ps -ef | grep kubelet ``` Find the file specified by the `--client-ca-file` argument. Run the following command: ``` stat -c %a ``` Verify that the permissions are `644` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/authentication/#x509-client-certs", + "DefaultValue": "By default no `--client-ca-file` is specified." + } + ] + }, + { + "Id": "4.1.8", + "Description": "Ensure that the client certificate authorities file ownership is set to root:root", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the certificate authorities file ownership is set to `root:root`.", + "RationaleStatement": "The certificate authorities file controls the authorities used to validate API requests. You should set its file ownership to maintain the integrity of the file. The file should be owned by `root:root`.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the following command to modify the ownership of the `--client-ca-file`. ``` chown root:root ```", + "AuditProcedure": "Run the following command: ``` ps -ef | grep kubelet ``` Find the file specified by the `--client-ca-file` argument. Run the following command: ``` stat -c %U:%G ``` Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/authentication/#x509-client-certs", + "DefaultValue": "By default no `--client-ca-file` is specified." + } + ] + }, + { + "Id": "4.1.9", + "Description": "If the kubelet config.yaml configuration file is being used validate permissions set to 600 or more restrictive", + "Checks": [ + "kubelet_config_yaml_permissions" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that if the kubelet refers to a configuration file with the `--config` argument, that file has permissions of 600 or more restrictive.", + "RationaleStatement": "The kubelet reads various parameters, including security settings, from a config file specified by the `--config` argument. If this file is specified you should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the following command (using the config file location identified in the Audit step) ``` chmod 600 /var/lib/kubelet/config.yaml ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet config yaml file. Please set $kubelet_config_yaml= based on the file location on your system for example: ``` export kubelet_config_yaml=/var/lib/kubelet/config.yaml ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %a /var/lib/kubelet/config.yaml ``` Verify that the permissions are `600` or more restrictive.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/", + "DefaultValue": "By default, the /var/lib/kubelet/config.yaml file as set up by `kubeadm` has permissions of 600." + } + ] + }, + { + "Id": "4.1.10", + "Description": "If the kubelet config.yaml configuration file is being used validate file ownership is set to root:root", + "Checks": [ + "kubelet_config_yaml_ownership" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.1 Worker Node Configuration Files", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Ensure that if the kubelet refers to a configuration file with the `--config` argument, that file is owned by root:root.", + "RationaleStatement": "The kubelet reads various parameters, including security settings, from a config file specified by the `--config` argument. If this file is specified you should restrict its file permissions to maintain the integrity of the file. The file should be owned by root:root.", + "ImpactStatement": "None", + "RemediationProcedure": "Run the following command (using the config file location identied in the Audit step) ``` chown root:root /etc/kubernetes/kubelet.conf ```", + "AuditProcedure": "Automated AAC auditing has been modified to allow CIS-CAT to input a variable for the / of the kubelet config yaml file. Please set $kubelet_config_yaml= based on the file location on your system for example: ``` export kubelet_config_yaml=/var/lib/kubelet/config.yaml ``` To perform the audit manually: Run the below command (based on the file location on your system) on the each worker node. For example, ``` stat -c %U:%G /var/lib/kubelet/config.yaml ```Verify that the ownership is set to `root:root`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/", + "DefaultValue": "By default, `/var/lib/kubelet/config.yaml` file as set up by `kubeadm` is owned by `root:root`." + } + ] + }, + { + "Id": "4.2.1", + "Description": "Ensure that the --anonymous-auth argument is set to false", + "Checks": [ + "kubelet_disable_anonymous_auth" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Disable anonymous requests to the Kubelet server.", + "RationaleStatement": "When enabled, requests that are not rejected by other configured authentication methods are treated as anonymous requests. These requests are then served by the Kubelet server. You should rely on authentication to authorize access and disallow anonymous requests.", + "ImpactStatement": "Anonymous requests will be rejected.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `authentication: anonymous: enabled` to `false`. If using executable arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_SYSTEM_PODS_ARGS` variable. ``` --anonymous-auth=false ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "If using a Kubelet configuration file, check that there is an entry for `authentication: anonymous: enabled` set to `false`. Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the `--anonymous-auth` argument is set to `false`. This executable argument may be omitted, provided there is a corresponding entry set to `false` in the Kubelet config file.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://kubernetes.io/docs/admin/kubelet-authentication-authorization/#kubelet-authentication", + "DefaultValue": "By default, anonymous access is enabled." + } + ] + }, + { + "Id": "4.2.2", + "Description": "Ensure that the --authorization-mode argument is not set to AlwaysAllow", + "Checks": [ + "kubelet_authorization_mode" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Do not allow all requests. Enable explicit authorization.", + "RationaleStatement": "Kubelets, by default, allow all authenticated requests (even anonymous ones) without needing explicit authorization checks from the apiserver. You should restrict this behavior and only allow explicitly authorized requests.", + "ImpactStatement": "Unauthorized requests will be denied.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `authorization: mode` to `Webhook`. If using executable arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_AUTHZ_ARGS` variable. ``` --authorization-mode=Webhook ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` If the `--authorization-mode` argument is present check that it is not set to `AlwaysAllow`. If it is not present check that there is a Kubelet config file specified by `--config`, and that file sets `authorization: mode` to something other than `AlwaysAllow`. It is also possible to review the running configuration of a Kubelet via the `/configz` endpoint on the Kubelet API port (typically `10250/TCP`). Accessing these with appropriate credentials will provide details of the Kubelet's configuration.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://kubernetes.io/docs/admin/kubelet-authentication-authorization/#kubelet-authentication", + "DefaultValue": "By default, `--authorization-mode` argument is set to `AlwaysAllow`." + } + ] + }, + { + "Id": "4.2.3", + "Description": "Ensure that the --client-ca-file argument is set as appropriate", + "Checks": [ + "kubelet_client_ca_file_set" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Enable Kubelet authentication using certificates.", + "RationaleStatement": "The connections from the apiserver to the kubelet are used for fetching logs for pods, attaching (through kubectl) to running pods, and using the kubelet’s port-forwarding functionality. These connections terminate at the kubelet’s HTTPS endpoint. By default, the apiserver does not verify the kubelet’s serving certificate, which makes the connection subject to man-in-the-middle attacks, and unsafe to run over untrusted and/or public networks. Enabling Kubelet certificate authentication ensures that the apiserver could authenticate the Kubelet before submitting any requests.", + "ImpactStatement": "You require TLS to be configured on apiserver as well as kubelets.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `authentication: x509: clientCAFile` to the location of the client CA file. If using command line arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_AUTHZ_ARGS` variable. ``` --client-ca-file= ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the `--client-ca-file` argument exists and is set to the location of the client certificate authority file. If the `--client-ca-file` argument is not present, check that there is a Kubelet config file specified by `--config`, and that the file sets `authentication: x509: clientCAFile` to the location of the client certificate authority file.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/", + "DefaultValue": "By default, `--client-ca-file` argument is not set." + } + ] + }, + { + "Id": "4.2.4", + "Description": "Verify that if defined, readOnlyPort is set to 0", + "Checks": [ + "kubelet_disable_read_only_port" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Disable the read-only port.", + "RationaleStatement": "The Kubelet process provides a read-only API in addition to the main Kubelet API. Unauthenticated access is provided to this read-only API which could possibly retrieve potentially sensitive information about the cluster.", + "ImpactStatement": "Removal of the read-only port will require that any service which made use of it will need to be re-configured to use the main Kubelet API.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `readOnlyPort` to `0`. If using command line arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_SYSTEM_PODS_ARGS` variable. ``` --read-only-port=0 ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the `--read-only-port` argument exists and is set to `0`. If the `--read-only-port` argument is not present, check that there is a Kubelet config file specified by `--config`. Check that if there is a `readOnlyPort` entry in the file, it is set to `0`.", + "AdditionalInformation": "https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://github.com/kubernetes/kubernetes/blob/6cedc0853faa118df0ba3d41b48b993422ad3df6/staging/src/k8s.io/kubelet/config/v1beta1/types.go#L142", + "DefaultValue": "" + } + ] + }, + { + "Id": "4.2.5", + "Description": "Ensure that the --streaming-connection-idle-timeout argument is not set to 0", + "Checks": [ + "kubelet_streaming_connection_timeout" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Do not disable timeouts on streaming connections.", + "RationaleStatement": "Setting idle timeouts ensures that you are protected against Denial-of-Service attacks, inactive connections and running out of ephemeral ports. **Note:** By default, `--streaming-connection-idle-timeout` is set to 4 hours which might be too high for your environment. Setting this as appropriate would additionally ensure that such streaming connections are timed out after serving legitimate use cases.", + "ImpactStatement": "Long-lived connections could be interrupted.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `streamingConnectionIdleTimeout` to a value other than 0. If using command line arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_SYSTEM_PODS_ARGS` variable. ``` --streaming-connection-idle-timeout=5m ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the `--streaming-connection-idle-timeout` argument is not set to `0`. If the argument is not present, and there is a Kubelet config file specified by `--config`, check that it does not set `streamingConnectionIdleTimeout` to 0.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://github.com/kubernetes/kubernetes/pull/18552", + "DefaultValue": "By default, `--streaming-connection-idle-timeout` is set to 4 hours." + } + ] + }, + { + "Id": "4.2.6", + "Description": "Ensure that the --make-iptables-util-chains argument is set to true", + "Checks": [ + "kubelet_manage_iptables" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Allow Kubelet to manage iptables.", + "RationaleStatement": "Kubelets can automatically manage the required changes to iptables based on how you choose your networking options for the pods. It is recommended to let kubelets manage the changes to iptables. This ensures that the iptables configuration remains in sync with pods networking configuration. Manually configuring iptables with dynamic pod network configuration changes might hamper the communication between pods/containers and to the outside world. You might have iptables rules too restrictive or too open.", + "ImpactStatement": "Kubelet would manage the iptables on the system and keep it in sync. If you are using any other iptables management solution, then there might be some conflicts.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `makeIPTablesUtilChains: true`. If using command line arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and remove the `--make-iptables-util-chains` argument from the `KUBELET_SYSTEM_PODS_ARGS` variable. Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that if the `--make-iptables-util-chains` argument exists then it is set to `true`. If the `--make-iptables-util-chains` argument does not exist, and there is a Kubelet config file specified by `--config`, verify that the file does not set `makeIPTablesUtilChains` to `false`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/", + "DefaultValue": "By default, `--make-iptables-util-chains` argument is set to `true`." + } + ] + }, + { + "Id": "4.2.7", + "Description": "Ensure that the --hostname-override argument is not set", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Do not override node hostnames.", + "RationaleStatement": "Overriding hostnames could potentially break TLS setup between the kubelet and the apiserver. Additionally, with overridden hostnames, it becomes increasingly difficult to associate logs with a particular node and process them for security analytics. Hence, you should setup your kubelet nodes with resolvable FQDNs and avoid overriding the hostnames with IPs.", + "ImpactStatement": "Some cloud providers may require this flag to ensure that hostname matches names issued by the cloud provider. In these environments, this recommendation should not apply.", + "RemediationProcedure": "Edit the kubelet service file `/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` on each worker node and remove the `--hostname-override` argument from the `KUBELET_SYSTEM_PODS_ARGS` variable. Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that `--hostname-override` argument does not exist. **Note** This setting is not configurable via the Kubelet config file.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://github.com/kubernetes/kubernetes/issues/22063", + "DefaultValue": "By default, `--hostname-override` argument is not set." + } + ] + }, + { + "Id": "4.2.8", + "Description": "Ensure that the eventRecordQPS argument is set to a level which ensures appropriate event capture", + "Checks": [ + "kubelet_event_record_qps" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 2 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Security relevant information should be captured. The eventRecordQPS on the Kubelet configuration can be used to limit the rate at which events are gathered and sets the maximum event creations per second. Setting this too low could result in relevant events not being logged, however the unlimited setting of `0` could result in a denial of service on the kubelet.", + "RationaleStatement": "It is important to capture all events and not restrict event creation. Events are an important source of security information and analytics that ensure that your environment is consistently monitored using the event data.", + "ImpactStatement": "Setting this parameter to `0` could result in a denial of service condition due to excessive events being created. The cluster's event processing and storage systems should be scaled to handle expected event loads.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `eventRecordQPS:` to an appropriate level. If using command line arguments, edit the kubelet service file `/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` on each worker node and set the below parameter in `KUBELET_ARGS` variable. Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` sudo grep eventRecordQPS /etc/systemd/system/kubelet.service.d/10-kubeadm.conf ``` or If using command line arguments, kubelet service file is located /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf ``` sudo grep eventRecordQPS /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf ``` Review the value set for the argument and determine whether this has been set to an appropriate level for the cluster. If the argument does not exist, check that there is a Kubelet config file specified by `--config` and review the value in this location. If using command line arguments", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/kubelet/:https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/kubeletconfig/v1beta1/types.go", + "DefaultValue": "By default, eventRecordQPS argument is set to `5`." + } + ] + }, + { + "Id": "4.2.9", + "Description": "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate", + "Checks": [ + "kubelet_tls_cert_and_key" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Setup TLS connection on the Kubelets.", + "RationaleStatement": "The connections from the apiserver to the kubelet are used for fetching logs for pods, attaching (through kubectl) to running pods, and using the kubelet’s port-forwarding functionality. These connections terminate at the kubelet’s HTTPS endpoint. By default, the apiserver does not verify the kubelet’s serving certificate, which makes the connection subject to man-in-the-middle attacks, and unsafe to run over untrusted and/or public networks.", + "ImpactStatement": "", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set tlsCertFile to the location of the certificate file to use to identify this Kubelet, and tlsPrivateKeyFile to the location of the corresponding private key file. If using command line arguments, edit the kubelet service file /etc/kubernetes/kubelet.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= --tls-private-key-file= Based on your system, restart the kubelet service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the --tls-cert-file and --tls-private-key-file arguments exist and they are set as appropriate. If these arguments are not present, check that there is a Kubelet config specified by --config and that it contains appropriate settings for tlsCertFile and tlsPrivateKeyFile.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "" + } + ] + }, + { + "Id": "4.2.10", + "Description": "Ensure that the --rotate-certificates argument is not set to false", + "Checks": [ + "kubelet_rotate_certificates" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Automated", + "Description": "Enable kubelet client certificate rotation.", + "RationaleStatement": "The `--rotate-certificates` setting causes the kubelet to rotate its client certificates by creating new CSRs as its existing credentials expire. This automated periodic rotation ensures that the there is no downtime due to expired certificates and thus addressing availability in the CIA security triad. **Note:** This recommendation only applies if you let kubelets get their certificates from the API server. In case your kubelet certificates come from an outside authority/tool (e.g. Vault) then you need to take care of rotation yourself. **Note:** This feature also require the `RotateKubeletClientCertificate` feature gate to be enabled (which is the default since Kubernetes v1.7)", + "ImpactStatement": "None", + "RemediationProcedure": "If using a Kubelet config file, edit the file to add the line `rotateCertificates: true` or remove it altogether to use the default value. If using command line arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and remove `--rotate-certificates=false` argument from the `KUBELET_CERTIFICATE_ARGS` variable or set --rotate-certificates=true . Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that the `RotateKubeletServerCertificate` argument is not present, or is set to `true`. If the RotateKubeletServerCertificate argument is not present, verify that if there is a Kubelet config file specified by `--config`, that file does not contain `RotateKubeletServerCertificate: false`.", + "AdditionalInformation": "", + "References": "https://github.com/kubernetes/kubernetes/pull/41912:https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration:https://kubernetes.io/docs/imported/release/notes/:https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/", + "DefaultValue": "By default, kubelet client certificate rotation is enabled." + } + ] + }, + { + "Id": "4.2.11", + "Description": "Verify that the RotateKubeletServerCertificate argument is set to true", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Enable kubelet server certificate rotation.", + "RationaleStatement": "`RotateKubeletServerCertificate` causes the kubelet to both request a serving certificate after bootstrapping its client credentials and rotate the certificate as its existing credentials expire. This automated periodic rotation ensures that the there are no downtimes due to expired certificates and thus addressing availability in the CIA security triad. Note: This recommendation only applies if you let kubelets get their certificates from the API server. In case your kubelet certificates come from an outside authority/tool (e.g. Vault) then you need to take care of rotation yourself.", + "ImpactStatement": "None", + "RemediationProcedure": "Edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the below parameter in `KUBELET_CERTIFICATE_ARGS` variable. ``` --feature-gates=RotateKubeletServerCertificate=true ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "Ignore this check if serverTLSBootstrap is true in the kubelet config file or if the --rotate-server-certificates parameter is set on kubelet Run the following command on each node: ``` ps -ef | grep kubelet ``` Verify that `RotateKubeletServerCertificate` argument exists and is set to `true`.", + "AdditionalInformation": "", + "References": "https://github.com/kubernetes/kubernetes/pull/45059:https://kubernetes.io/docs/admin/kubelet-tls-bootstrapping/#kubelet-configuration", + "DefaultValue": "By default, kubelet server certificate rotation is enabled." + } + ] + }, + { + "Id": "4.2.12", + "Description": "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers", + "Checks": [ + "kubelet_strong_ciphers_only" + ], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the Kubelet is configured to only use strong cryptographic ciphers.", + "RationaleStatement": "TLS ciphers have had a number of known vulnerabilities and weaknesses, which can reduce the protection provided by them. By default Kubernetes supports a number of TLS ciphersuites including some that have security concerns, weakening the protection provided.", + "ImpactStatement": "Kubelet clients that cannot support modern cryptographic ciphers will not be able to make connections to the Kubelet API.", + "RemediationProcedure": "If using a Kubelet config file, edit the file to set `tlsCipherSuites:` to `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256` or to a subset of these values. If using executable arguments, edit the kubelet service file `/etc/kubernetes/kubelet.conf` on each worker node and set the `--tls-cipher-suites` parameter as follows, or to a subset of these values. ``` --tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 ``` Based on your system, restart the `kubelet` service. For example: ``` systemctl daemon-reload systemctl restart kubelet.service ```", + "AuditProcedure": "The set of cryptographic ciphers currently considered secure is the following: - `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305` - `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305` - `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` - `TLS_RSA_WITH_AES_256_GCM_SHA384` - `TLS_RSA_WITH_AES_128_GCM_SHA256` Run the following command on each node: ``` ps -ef | grep kubelet ``` If the `--tls-cipher-suites` argument is present, ensure it only contains values included in this set. If it is not present check that there is a Kubelet config file specified by `--config`, and that file sets `tlsCipherSuites:` to only include values from this set.", + "AdditionalInformation": "The list chosen above should be fine for modern clients. It's essentially the list from the Mozilla Modern cipher option with the ciphersuites supporting CBC mode removed, as CBC has traditionally had a lot of issues", + "References": "", + "DefaultValue": "By default the Kubernetes API server supports a wide range of TLS ciphers" + } + ] + }, + { + "Id": "4.2.13", + "Description": "Ensure that a limit is set on pod PIDs", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the Kubelet sets limits on the number of PIDs that can be created by pods running on the node.", + "RationaleStatement": "By default pods running in a cluster can consume any number of PIDs, potentially exhausting the resources available on the node. Setting an appropriate limit reduces the risk of a denial of service attack on cluster nodes.", + "ImpactStatement": "Setting this value will restrict the number of processes per pod. If this limit is lower than the number of PIDs required by a pod it will not operate.", + "RemediationProcedure": "Decide on an appropriate level for this parameter and set it, either via the `--pod-max-pids` command line parameter or the `PodPidsLimit` configuration file setting.", + "AuditProcedure": "Review the Kubelet's start-up parameters for the value of `--pod-max-pids`, and check the Kubelet configuration file for the `PodPidsLimit` . If neither of these values is set, then there is no limit in place.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/policy/pid-limiting/#pod-pid-limits", + "DefaultValue": "By default the number of PIDs is not limited." + } + ] + }, + { + "Id": "4.2.14", + "Description": "Ensure that the --seccomp-default parameter is set to true", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensure that the Kubelet enforces the use of the RuntimeDefault seccomp profile", + "RationaleStatement": "By default, Kubernetes disables the seccomp profile which ships with most container runtimes. Setting this parameter will ensure workloads running on the node are protected by the runtime's seccomp profile.", + "ImpactStatement": "Setting this will remove some rights from pods running on the node.", + "RemediationProcedure": "Set the parameter, either via the `--seccomp-default` command line parameter or the `seccompDefault` configuration file setting.", + "AuditProcedure": "Review the Kubelet's start-up parameters for the value of `--seccomp-default`, and check the Kubelet configuration file for the `seccompDefault` . If neither of these values is set, then the seccomp profile is not in use.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tutorials/security/seccomp/#enable-the-use-of-runtimedefault-as-the-default-seccomp-profile-for-all-workloads", + "DefaultValue": "By default the seccomp profile is not enabled." + } + ] + }, + { + "Id": "4.2.15", + "Description": "Ensure that the --IPAddressDeny is set to any", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.2 Kubelet", + "Profile": "Level 2 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Ensuring that `--IPAddressDeny` is set to Any will facilitate allowlisting of only IP addresses that are explicitly set with the `--IPAddressAllow` parameter which will block unspecified IP addresses from communicating with the **kubelet** component.", + "RationaleStatement": "By default, Kubernetes allows any IP address to communicate with the **kubelet** component IP restrictions and IP whitelisting are security best practices and reduce the attack surface of the **kubelet**.", + "ImpactStatement": "Configuring the setting `IPAddressDeny=any` will deny service to any IP address not specified in the complimentary setting `IPAddressDeny=any` configuration parameter. Applying `IPAddressDeny=any` alone will completely disable communication with the component.", + "RemediationProcedure": "`IPAddressDeny=any` `IPAddressAllow={{ kubelet_secure_addresses }}` *Note kubelet_secure_addresses: localhost link-local {{ kube_pods_subnets | regex_replace(',', ' ') }} {{ kube_node_addresses }} {{ loadbalancer_apiserver.address | default('')", + "AuditProcedure": "Review the Kubelet's start-up parameters for the value of `--IPAddressDeny`, and check the Kubelet configuration file for `IPAddressDeny=any`. If this entry is present it should be accompanied by `IPAddressAllow={{ kubelet_secure_addresses }}` to allow the control plane to communicate with the component.", + "AdditionalInformation": "", + "References": "https://github.com/kubernetes-sigs/kubespray/pull/9194/files:https://kubernetes.io/docs/concepts/services-networking/network-policies/", + "DefaultValue": "By default IPAddressDeny is not enabled." + } + ] + }, + { + "Id": "4.3.1", + "Description": "Ensure that the kube-proxy metrics service is bound to localhost", + "Checks": [], + "Attributes": [ + { + "Section": "4 Worker Nodes", + "SubSection": "4.3 kube-proxy", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Do not bind the kube-proxy metrics port to non-loopback addresses.", + "RationaleStatement": "kube-proxy has two APIs which provided access to information about the service and can be bound to network ports. The metrics API service includes endpoints (`/metrics` and `/configz`) which disclose information about the configuration and operation of kube-proxy. These endpoints should not be exposed to untrusted networks as they do not support encryption or authentication to restrict access to the data they provide.", + "ImpactStatement": "3rd party services which try to access metrics or configuration information related to kube-proxy will require access to the localhost interface of the node.", + "RemediationProcedure": "Modify or remove any values which bind the metrics service to a non-localhost address", + "AuditProcedure": "review the start-up flags provided to kube proxy Run the following command on each node: ``` ps -ef | grep -i kube-proxy ``` Ensure that the `--metrics-bind-address` parameter is not set to a value other than 127.0.0.1. From the output of this command gather the location specified in the `--config` parameter. Review any file stored at that location and ensure that it does not specify a value other than 127.0.0.1 for `metricsBindAddress`.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/", + "DefaultValue": "The default value is `127.0.0.1:10249`" + } + ] + }, + { + "Id": "5.1.1", + "Description": "Ensure that the cluster-admin role is only used where required", + "Checks": [ + "rbac_cluster_admin_usage" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The RBAC role `cluster-admin` provides wide-ranging powers over the environment and should be used only where and when needed.", + "RationaleStatement": "Kubernetes provides a set of default roles where RBAC is used. Some of these roles such as `cluster-admin` provide wide-ranging privileges which should only be applied where absolutely necessary. Roles such as `cluster-admin` allow super-user access to perform any action on any resource. When used in a `ClusterRoleBinding`, it gives full control over every resource in the cluster and in all namespaces. When used in a `RoleBinding`, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.", + "ImpactStatement": "Care should be taken before removing any `clusterrolebindings` from the environment to ensure they were not required for operation of the cluster. Specifically, modifications should not be made to `clusterrolebindings` with the `system:` prefix as they are required for the operation of system components.", + "RemediationProcedure": "Identify all clusterrolebindings to the cluster-admin role. Check if they are used and if they need this role or if they could use a role with fewer privileges. Where possible, first bind users to a lower privileged role and then remove the clusterrolebinding to the cluster-admin role : ``` kubectl delete clusterrolebinding [name] ```", + "AuditProcedure": "Obtain a list of the principals who have access to the `cluster-admin` role by reviewing the `clusterrolebinding` output for each role binding that has access to the `cluster-admin` role. ``` kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name ``` Review each principal listed and ensure that `cluster-admin` privilege is required for it.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/authorization/rbac/#user-facing-roles", + "DefaultValue": "By default a single `clusterrolebinding` called `cluster-admin` is provided with the `system:masters` group as its principal." + } + ] + }, + { + "Id": "5.1.2", + "Description": "Minimize access to secrets", + "Checks": [ + "rbac_minimize_secret_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The Kubernetes API stores secrets, which may be service account tokens for the Kubernetes API or credentials used by workloads in the cluster. Access to these secrets should be restricted to the smallest possible group of users to reduce the risk of privilege escalation.", + "RationaleStatement": "Inappropriate access to secrets stored within the Kubernetes cluster can allow for an attacker to gain additional access to the Kubernetes cluster or external resources whose credentials are stored as secrets.", + "ImpactStatement": "Care should be taken not to remove access to secrets to system components which require this for their operation", + "RemediationProcedure": "Where possible, restrict access to secret objects in the cluster by removing get, list, and watch permissions.", + "AuditProcedure": "Review the users who have `get`, `list`, or `watch` access to `secrets` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "By default in a kubeadm cluster the following list of principals have `get` privileges on `secret` objects ``` CLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE cluster-admin system:masters Group system:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system system:controller:expand-controller expand-controller ServiceAccount kube-system system:controller:generic-garbage-collector generic-garbage-collector ServiceAccount kube-system system:controller:namespace-controller namespace-controller ServiceAccount kube-system system:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system system:kube-controller-manager system:kube-controller-manager User ```" + } + ] + }, + { + "Id": "5.1.3", + "Description": "Minimize wildcard use in Roles and ClusterRoles", + "Checks": [ + "rbac_minimize_wildcard_use_roles" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Worker Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard * which matches all items. Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product.", + "RationaleStatement": "The principle of least privilege recommends that users are provided only the access required for their role and nothing more. The use of wildcard rights grants is likely to provide excessive rights to the Kubernetes API.", + "ImpactStatement": "", + "RemediationProcedure": "Where possible replace any use of wildcards in ClusterRoles and Roles with specific objects or actions.", + "AuditProcedure": "Retrieve the roles defined across each namespaces in the cluster and review for wildcards ``` kubectl get roles --all-namespaces -o yaml ``` Retrieve the cluster roles defined in the cluster and review for wildcards ``` kubectl get clusterroles -o yaml ```", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.1.4", + "Description": "Minimize access to create pods", + "Checks": [ + "rbac_minimize_pod_creation_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The ability to create pods in a namespace can provide a number of opportunities for privilege escalation, such as assigning privileged service accounts to these pods or mounting hostPaths with access to sensitive data (unless Pod Security Policies are implemented to restrict this access) As such, access to create new pods should be restricted to the smallest possible group of users.", + "RationaleStatement": "The ability to create pods in a cluster opens up possibilities for privilege escalation and should be restricted, where possible.", + "ImpactStatement": "Care should be taken not to remove access to pods to system components which require this for their operation", + "RemediationProcedure": "Where possible, remove `create` access to `pod` objects in the cluster.", + "AuditProcedure": "Review the users who have create access to pod objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "By default in a kubeadm cluster the following list of principals have `create` privileges on `pod` objects ``` CLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE cluster-admin system:masters Group system:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system system:controller:daemon-set-controller daemon-set-controller ServiceAccount kube-system system:controller:job-controller job-controller ServiceAccount kube-system system:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system system:controller:replicaset-controller replicaset-controller ServiceAccount kube-system system:controller:replication-controller replication-controller ServiceAccount kube-system system:controller:statefulset-controller statefulset-controller ServiceAccount kube-system ```" + } + ] + }, + { + "Id": "5.1.5", + "Description": "Ensure that default service accounts are not actively used.", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The `default` service account should not be used to ensure that rights granted to applications can be more easily audited and reviewed.", + "RationaleStatement": "Kubernetes provides a default service account which is used by cluster workloads where no specific service account is assigned to the pod. Where access to the Kubernetes API from a pod is required, a specific service account should be created for that pod, and rights granted to that service account. The default service account should be configured to ensure that it does not automatically provide a service account token, and it must not have any non-default role bindings or custom role assignments", + "ImpactStatement": "All workloads which require access to the Kubernetes API will require an explicit service account to be created.", + "RemediationProcedure": "Create explicit service accounts wherever a Kubernetes workload requires specific access to the Kubernetes API server. Modify the configuration of each default service account to include this value ``` automountServiceAccountToken: false ```", + "AuditProcedure": "For each namespace in the cluster, review the rights assigned to the default service account and ensure that it has no roles or cluster roles bound to it apart from the defaults. Additionally ensure that the `automountServiceAccountToken: false` setting is in place for each default service account.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/", + "DefaultValue": "By default the `default` service account allows for its service account token to be mounted in pods in its namespace." + } + ] + }, + { + "Id": "5.1.6", + "Description": "Ensure that Service Account Tokens are only mounted where necessary", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server", + "RationaleStatement": "Mounting service account tokens inside pods can provide an avenue for privilege escalation attacks where an attacker is able to compromise a single pod in the cluster. Avoiding mounting these tokens removes this attack avenue.", + "ImpactStatement": "Pods mounted without service account tokens will not be able to communicate with the API server, except where the resource is available to unauthenticated principals.", + "RemediationProcedure": "Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it.", + "AuditProcedure": "Review pod and service account objects in the cluster and ensure that the option below is set, unless the resource explicitly requires this access. ``` automountServiceAccountToken: false ```", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/", + "DefaultValue": "By default, all pods get a service account token mounted in them." + } + ] + }, + { + "Id": "5.1.7", + "Description": "Avoid use of system:masters group", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The special group `system:masters` should not be used to grant permissions to any user or service account, except where strictly necessary (e.g. bootstrapping access prior to RBAC being fully available)", + "RationaleStatement": "The `system:masters` group has unrestricted access to the Kubernetes API hard-coded into the API server source code. An authenticated user who is a member of this group cannot have their access reduced, even if all bindings and cluster role bindings which mention it, are removed. When combined with client certificate authentication, use of this group can allow for irrevocable cluster-admin level credentials to exist for a cluster.", + "ImpactStatement": "Once the RBAC system is operational in a cluster `system:masters` should not be specifically required, as ordinary bindings from principals to the `cluster-admin` cluster role can be made where unrestricted access is required.", + "RemediationProcedure": "Remove the `system:masters` group from all users in the cluster.", + "AuditProcedure": "Review a list of all credentials which have access to the cluster and ensure that the group `system:masters` is not used.", + "AdditionalInformation": "", + "References": "https://github.com/kubernetes/kubernetes/blob/master/pkg/registry/rbac/escalation_check.go#L38", + "DefaultValue": "By default some clusters will create a break glass client certificate which is a member of this group. Access to this client certificate should be carefully controlled and it should not be used for general cluster operations." + } + ] + }, + { + "Id": "5.1.8", + "Description": "Limit use of the Bind, Impersonate and Escalate permissions in the Kubernetes cluster", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Cluster roles and roles with the impersonate, bind or escalate permissions should not be granted unless strictly required. Each of these permissions allow a particular subject to escalate their privileges beyond those explicitly granted by cluster administrators", + "RationaleStatement": "The impersonate privilege allows a subject to impersonate other users gaining their rights to the cluster. The bind privilege allows the subject to add a binding to a cluster role or role which escalates their effective permissions in the cluster. The escalate privilege allows a subject to modify cluster roles to which they are bound, increasing their rights to that level. Each of these permissions has the potential to allow for privilege escalation to cluster-admin level.", + "ImpactStatement": "There are some cases where these permissions are required for cluster service operation, and care should be taken before removing these permissions from system service accounts.", + "RemediationProcedure": "Where possible, remove the impersonate, bind, and escalate rights from subjects.", + "AuditProcedure": "Review the users who have access to cluster roles or roles which provide the impersonate, bind, or escalate privileges.", + "AdditionalInformation": "", + "References": "https://raesene.github.io/blog/2020/12/12/Escalating_Away/:https://raesene.github.io/blog/2021/01/16/Getting-Into-A-Bind-with-Kubernetes/", + "DefaultValue": "In a default kubeadm cluster, the system:masters group and clusterrole-aggregation-controller service account have access to the escalate privilege. The system:masters group also has access to bind and impersonate." + } + ] + }, + { + "Id": "5.1.9", + "Description": "Minimize access to create persistent volumes", + "Checks": [ + "rbac_minimize_pv_creation_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "The ability to create persistent volumes in a cluster can provide an opportunity for privilege escalation, via the creation of `hostPath` volumes. As persistent volumes are not covered by Pod Security Admission, a user with access to create persistent volumes may be able to get access to sensitive files from the underlying host even where restrictive Pod Security Admission policies are in place.", + "RationaleStatement": "The ability to create persistent volumes in a cluster opens up possibilities for privilege escalation and should be restricted, where possible.", + "ImpactStatement": "", + "RemediationProcedure": "Where possible, remove `create` access to `PersistentVolume` objects in the cluster.", + "AuditProcedure": "Review the users who have create access to `PersistentVolume` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/rbac-good-practices/#persistent-volume-creation", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.1.10", + "Description": "Minimize access to the proxy sub-resource of nodes", + "Checks": [ + "rbac_minimize_node_proxy_subresource_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Users with access to the `Proxy` sub-resource of `Node` objects automatically have permissions to use the kubelet API, which may allow for privilege escalation or bypass cluster security controls such as audit logs. The kubelet provides an API which includes rights to execute commands in any container running on the node. Access to this API is covered by permissions to the main Kubernetes API via the `node` object. The proxy sub-resource specifically allows wide ranging access to the kubelet API. Direct access to the kubelet API bypasses controls like audit logging (there is no audit log of kubelet API access) and admission control.", + "RationaleStatement": "The ability to use the `proxy` sub-resource of `node` objects opens up possibilities for privilege escalation and should be restricted, where possible.", + "ImpactStatement": "", + "RemediationProcedure": "Where possible, remove access to the `proxy` sub-resource of `node` objects.", + "AuditProcedure": "Review the users who have access to the `proxy` sub-resource of `node` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/rbac-good-practices/#access-to-proxy-subresource-of-nodes:https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/#kubelet-authorization", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.1.11", + "Description": "Minimize access to the approval sub-resource of certificatesigningrequests objects", + "Checks": [ + "rbac_minimize_csr_approval_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Users with access to the update the `approval` sub-resource of `CertificateSigningRequests` objects can approve new client certificates for the Kubernetes API effectively allowing them to create new high-privileged user accounts. This can allow for privilege escalation to full cluster administrator, depending on users configured in the cluster", + "RationaleStatement": "The ability to update certificate signing requests should be limited.", + "ImpactStatement": "", + "RemediationProcedure": "Where possible, remove access to the `approval` sub-resource of `CertificateSigningRequests` objects.", + "AuditProcedure": "Review the users who have access to update the `approval` sub-resource of `CertificateSigningRequests` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/rbac-good-practices/#csrs-and-certificate-issuing", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.1.12", + "Description": "Minimize access to webhook configuration objects", + "Checks": [ + "rbac_minimize_webhook_config_access" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Users with rights to create/modify/delete `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` can control webhooks that can read any object admitted to the cluster, and in the case of mutating webhooks, also mutate admitted objects. This could allow for privilege escalation or disruption of the operation of the cluster.", + "RationaleStatement": "The ability to manage webhook configuration should be limited", + "ImpactStatement": "", + "RemediationProcedure": "Where possible, remove access to the `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` objects", + "AuditProcedure": "Review the users who have access to `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/rbac-good-practices/#control-admission-webhooks", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.1.13", + "Description": "Minimize access to the service account token creation", + "Checks": [ + "rbac_minimize_service_account_token_creation" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.1 RBAC and Service Accounts", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Users with rights to create new service account tokens at a cluster level, can create long-lived privileged credentials in the cluster. This could allow for privilege escalation and persistent access to the cluster, even if the users account has been revoked.", + "RationaleStatement": "The ability to create service account tokens should be limited.", + "ImpactStatement": "", + "RemediationProcedure": "Where possible, remove access to the `token` sub-resource of `serviceaccount` objects.", + "AuditProcedure": "Review the users who have access to create the `token` sub-resource of `serviceaccount` objects in the Kubernetes API.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/rbac-good-practices/#token-request", + "DefaultValue": "" + } + ] + }, + { + "Id": "5.2.1", + "Description": "Ensure that the cluster has at least one active policy control mechanism in place", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Every Kubernetes cluster should have at least one policy control mechanism in place to enforce the other requirements in this section. This could be the in-built Pod Security Admission controller, or a third party policy control system.", + "RationaleStatement": "Without an active policy control mechanism, it is not possible to limit the use of containers with access to underlying cluster nodes, via mechanisms like privileged containers, or the use of hostPath volume mounts.", + "ImpactStatement": "Where policy control systems are in place, there is a risk that workloads required for the operation of the cluster may be stopped from running. Care is required when implementing admission control policies to ensure that this does not occur.", + "RemediationProcedure": "Ensure that either Pod Security Admission or an external policy control system is in place for every namespace which contains user workloads.", + "AuditProcedure": "Review the workloads deployed to the cluster to understand if Pod Security Admission or external admission control systems are in place.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-admission", + "DefaultValue": "By default, Pod Security Admission is enabled but no policies are in place." + } + ] + }, + { + "Id": "5.2.2", + "Description": "Minimize the admission of privileged containers", + "Checks": [ + "core_minimize_privileged_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run with the `securityContext.privileged` flag set to `true`.", + "RationaleStatement": "Privileged containers have access to all Linux Kernel capabilities and devices. A container running with full privileges can do almost everything that the host can do. This flag exists to allow special use-cases, like manipulating the network stack and accessing devices. There should be at least one admission control policy defined which does not permit privileged containers. If you need to run privileged containers, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `spec.containers[].securityContext.privileged: true`, `spec.initContainers[].securityContext.privileged: true` and `spec.ephemeralContainers[].securityContext.privileged: true` will not be permitted.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of privileged containers.", + "AuditProcedure": "Run the following command: `kubectl get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@..securityContext}{end}'`It will produce an inventory of all the privileged use on the cluster, if any (please, refer to a sample below). Further grepping can be done to automate each specific violation detection. calico-kube-controllers-57b57c56f-jtmk4: {} << No Elevated Privileges calico-node-c4xv4: {} {privileged:true} {privileged:true} {privileged:true} {privileged:true} << Violates 5.2.2 dashboard-metrics-scraper-7bc864c59-2m2xw: {seccompProfile:{type:RuntimeDefault}} {allowPrivilegeEscalation:false,readOnlyRootFilesystem:true,runAsGroup:2001,runAsUser:1001}", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of privileged containers." + } + ] + }, + { + "Id": "5.2.3", + "Description": "Minimize the admission of containers wishing to share the host process ID namespace", + "Checks": [ + "core_minimize_hostPID_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run with the `hostPID` flag set to true.", + "RationaleStatement": "A container running in the host's PID namespace can inspect processes running outside the container. If the container also has access to ptrace capabilities this can be used to escalate privileges outside of the container. There should be at least one admission control policy defined which does not permit containers to share the host PID namespace. If you need to run containers which require hostPID, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `spec.hostPID: true` will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Configure the Admission Controller to restrict the admission of `hostPID` containers.", + "AuditProcedure": "Fetch hostPID from each pod with `get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@.spec.hostPID}{end}'`", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of `hostPID` containers." + } + ] + }, + { + "Id": "5.2.4", + "Description": "Minimize the admission of containers wishing to share the host IPC namespace", + "Checks": [ + "core_minimize_hostIPC_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run with the `hostIPC` flag set to true.", + "RationaleStatement": "A container running in the host's IPC namespace can use IPC to interact with processes outside the container. There should be at least one admission control policy defined which does not permit containers to share the host IPC namespace. If you need to run containers which require hostIPC, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `spec.hostIPC: true` will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of `hostIPC` containers.", + "AuditProcedure": "Fetch hostIPC from each pod with `get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@.spec.hostIPC}{end}'`", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of `hostIPC` containers." + } + ] + }, + { + "Id": "5.2.5", + "Description": "Minimize the admission of containers wishing to share the host network namespace", + "Checks": [ + "core_minimize_hostNetwork_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run with the `hostNetwork` flag set to true.", + "RationaleStatement": "A container running in the host's network namespace could access the local loopback device, and could access network traffic to and from other pods. There should be at least one admission control policy defined which does not permit containers to share the host network namespace. If you need to run containers which require access to the host's network namespaces, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `spec.hostNetwork: true` will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of `hostNetwork` containers.", + "AuditProcedure": "Fetch hostNetwork from each pod with `get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@.spec.hostNetwork}{end}'`", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of `hostNetwork` containers." + } + ] + }, + { + "Id": "5.2.6", + "Description": "Minimize the admission of containers with allowPrivilegeEscalation", + "Checks": [ + "core_minimize_allowPrivilegeEscalation_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run with the `allowPrivilegeEscalation` flag set to true. Allowing this right can lead to a process running a container getting more rights than it started with. It's important to note that these rights are still constrained by the overall container sandbox, and this setting does not relate to the use of privileged containers.", + "RationaleStatement": "A container running with the `allowPrivilegeEscalation` flag set to `true` may have processes that can gain more privileges than their parent. There should be at least one admission control policy defined which does not permit containers to allow privilege escalation. The option exists (and is defaulted to true) to permit setuid binaries to run. If you have need to run containers which use setuid binaries or require privilege escalation, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `securityContext: allowPrivilegeEscalation: true` will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of containers with `securityContext: allowPrivilegeEscalation: true`", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that each policy disallows the admission of containers which allow privilege escalation. To fetch a list of pods which `allowPrivilegeEscalation` run this command: `get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@..securityContext}{end}'`", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on contained process ability to escalate privileges, within the context of the container." + } + ] + }, + { + "Id": "5.2.7", + "Description": "Minimize the admission of root containers", + "Checks": [ + "core_minimize_root_containers_admission" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers to be run as the root user.", + "RationaleStatement": "Containers may run as any Linux user. Containers which run as the root user, whilst constrained by Container Runtime security features still have a escalated likelihood of container breakout. Ideally, all containers should run as a defined non-UID 0 user. There should be at least one admission control policy defined which does not permit root containers. If you need to run root containers, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods with containers which run as the root user will not be permitted.", + "RemediationProcedure": "Create a policy for each namespace in the cluster, ensuring that either `MustRunAsNonRoot` or `MustRunAs` with the range of UIDs not including 0, is set.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that each policy restricts the use of root containers by setting `MustRunAsNonRoot` or `MustRunAs` with the range of UIDs not including 0.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the use of root containers and if a User is not specified in the image, the container will run as root." + } + ] + }, + { + "Id": "5.2.8", + "Description": "Minimize the admission of containers with the NET_RAW capability", + "Checks": [ + "core_minimize_net_raw_capability_admission" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers with the potentially dangerous NET_RAW capability.", + "RationaleStatement": "Containers run with a default set of capabilities as assigned by the Container Runtime. By default this can include potentially dangerous capabilities. With Docker as the container runtime the NET_RAW capability is enabled which may be misused by malicious containers. Ideally, all containers should drop this capability. There should be at least one admission control policy defined which does not permit containers with the NET_RAW capability. If you need to run containers with this capability, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods with containers which run with the NET_RAW capability will not be permitted.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of containers with the `NET_RAW` capability.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that at least one policy disallows the admission of containers with the `NET_RAW` capability.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/:https://www.nccgroup.trust/uk/our-research/abusing-privileged-and-unprivileged-linux-containers/", + "DefaultValue": "By default, there are no restrictions on the creation of containers with the `NET_RAW` capability." + } + ] + }, + { + "Id": "5.2.9", + "Description": "Minimize the admission of containers with added capabilities", + "Checks": [ + "core_minimize_containers_added_capabilities" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers with capabilities assigned beyond the default set.", + "RationaleStatement": "Containers run with a default set of capabilities as assigned by the Container Runtime. Capabilities outside this set can be added to containers which could expose them to risks of container breakout attacks. There should be at least one policy defined which prevents containers with capabilities beyond the default set from launching. If you need to run containers with additional capabilities, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods with containers which require capabilities outside the default set will not be permitted.", + "RemediationProcedure": "Ensure that `allowedCapabilities` is not present in policies for the cluster unless it is set to an empty array.", + "AuditProcedure": "Ensure that allowedCapabilities is not present in policies for the cluster unless it is set to an empty array. Run: kubectl get pods -A -o=jsonpath='{range .items[*]}{@.metadata.name}: {@..securityContext}{end}'", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/:https://www.nccgroup.trust/uk/our-research/abusing-privileged-and-unprivileged-linux-containers/", + "DefaultValue": "By default, there are no restrictions on adding capabilities to containers." + } + ] + }, + { + "Id": "5.2.10", + "Description": "Minimize the admission of containers with capabilities assigned", + "Checks": [ + "core_minimize_containers_capabilities_assigned" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers with capabilities", + "RationaleStatement": "Containers run with a default set of capabilities as assigned by the Container Runtime. Capabilities are parts of the rights generally granted on a Linux system to the root user. In many cases applications running in containers do not require any capabilities to operate, so from the perspective of the principal of least privilege use of capabilities should be minimized.", + "ImpactStatement": "Pods with containers require capabilities to operate will not be permitted.", + "RemediationProcedure": "Review the use of capabilities in applications running on your cluster. Where a namespace contains applications which do not require any Linux capabilities to operate consider adding a policy which forbids the admission of containers which do not drop all capabilities.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that at least one policy requires that capabilities are dropped by all containers.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/:https://www.nccgroup.trust/uk/our-research/abusing-privileged-and-unprivileged-linux-containers/", + "DefaultValue": "By default, there are no restrictions on the creation of containers with additional capabilities" + } + ] + }, + { + "Id": "5.2.11", + "Description": "Minimize the admission of Windows HostProcess Containers", + "Checks": [ + "core_minimize_admission_windows_hostprocess_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit Windows containers to be run with the `hostProcess` flag set to true.", + "RationaleStatement": "A Windows container making use of the `hostProcess` flag can interact with the underlying Windows cluster node. As per the Kubernetes documentation, this provides privileged access to the Windows node. Where Windows containers are used inside a Kubernetes cluster, there should be at least one admission control policy which does not permit `hostProcess` Windows containers. If you need to run Windows containers which require `hostProcess`, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `securityContext.windowsOptions.hostProcess: true` will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of `hostProcess` containers.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that each policy disallows the admission of `hostProcess` containers", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tasks/configure-pod-container/create-hostprocess-pod/:https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of `hostProcess` containers." + } + ] + }, + { + "Id": "5.2.12", + "Description": "Minimize the admission of HostPath volumes", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally admit containers which make use of `hostPath` volumes.", + "RationaleStatement": "A container which mounts a `hostPath` volume as part of its specification will have access to the filesystem of the underlying cluster node. The use of `hostPath` volumes may allow containers access to privileged areas of the node filesystem. There should be at least one admission control policy defined which does not permit containers to mount `hostPath` volumes. If you need to run containers which require `hostPath` volumes, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined which make use of `hostPath` volumes will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of containers which use `hostPath` volumes.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that each policy disallows the admission of containers with `hostPath` volumes.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the creation of `hostPath` volumes." + } + ] + }, + { + "Id": "5.2.13", + "Description": "Minimize the admission of containers which use HostPorts", + "Checks": [ + "core_minimize_admission_hostport_containers" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.2 Pod Security Standards", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Do not generally permit containers which require the use of HostPorts.", + "RationaleStatement": "Host ports connect containers directly to the host's network. This can bypass controls such as network policy. There should be at least one admission control policy defined which does not permit containers which require the use of HostPorts. If you need to run containers which require HostPorts, this should be defined in a separate policy and you should carefully check to ensure that only limited service accounts and users are given permission to use that policy.", + "ImpactStatement": "Pods defined with `hostPort` settings in either the container, initContainer or ephemeralContainer sections will not be permitted unless they are run under a specific policy.", + "RemediationProcedure": "Add policies to each namespace in the cluster which has user workloads to restrict the admission of containers which use `hostPort` sections.", + "AuditProcedure": "List the policies in use for each namespace in the cluster, ensure that each policy disallows the admission of containers which have `hostPort` sections.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "DefaultValue": "By default, there are no restrictions on the use of HostPorts." + } + ] + }, + { + "Id": "5.3.1", + "Description": "Ensure that the CNI in use supports Network Policies", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.3 Network Policies and CNI", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "There are a variety of CNI plugins available for Kubernetes. If the CNI in use does not support Network Policies it may not be possible to effectively restrict traffic in the cluster.", + "RationaleStatement": "Kubernetes network policies are enforced by the CNI plugin in use. As such it is important to ensure that the CNI plugin supports both Ingress and Egress network policies.", + "ImpactStatement": "None", + "RemediationProcedure": "If the CNI plugin in use does not support network policies, consideration should be given to making use of a different plugin, or finding an alternate mechanism for restricting traffic in the Kubernetes cluster.", + "AuditProcedure": "Review the documentation of CNI plugin in use by the cluster, and confirm that it supports Ingress and Egress network policies.", + "AdditionalInformation": "One example here is Flannel (https://github.com/coreos/flannel) which does not support Network policy unless Calico is also in use.", + "References": "https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/", + "DefaultValue": "This will depend on the CNI plugin in use." + } + ] + }, + { + "Id": "5.3.2", + "Description": "Ensure that all Namespaces have Network Policies defined", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.3 Network Policies and CNI", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Use network policies to isolate traffic in your cluster network.", + "RationaleStatement": "Running different applications on the same Kubernetes cluster creates a risk of one compromised application attacking a neighboring application. Network segmentation is important to ensure that containers can communicate only with those they are supposed to. A network policy is a specification of how selections of pods are allowed to communicate with each other and other network endpoints. Network Policies are namespace scoped. When a network policy is introduced to a given namespace, all traffic not allowed by the policy is denied. However, if there are no network policies in a namespace all traffic will be allowed into and out of the pods in that namespace.", + "ImpactStatement": "Once network policies are in use within a given namespace, traffic not explicitly allowed by a network policy will be denied. As such it is important to ensure that, when introducing network policies, legitimate traffic is not blocked.", + "RemediationProcedure": "Follow the documentation and create `NetworkPolicy` objects as you need them.", + "AuditProcedure": "Run the below command and review the `NetworkPolicy` objects created in the cluster. ``` kubectl get networkpolicy --all-namespaces ``` Ensure that each namespace defined in the cluster has at least one Network Policy.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/services-networking/networkpolicies/:https://octetz.com/posts/k8s-network-policy-apis:https://kubernetes.io/docs/tasks/configure-pod-container/declare-network-policy/", + "DefaultValue": "By default, network policies are not created." + } + ] + }, + { + "Id": "5.4.1", + "Description": "Prefer using secrets as files over secrets as environment variables", + "Checks": [ + "core_no_secrets_envs" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.4 Secrets Management", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes supports mounting secrets as data volumes or as environment variables. Minimize the use of environment variable secrets.", + "RationaleStatement": "It is reasonably common for application code to log out its environment (particularly in the event of an error). This will include any secret values passed in as environment variables, so secrets can easily be exposed to any user or entity who has access to the logs.", + "ImpactStatement": "Application code which expects to read secrets in the form of environment variables would need modification", + "RemediationProcedure": "If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables.", + "AuditProcedure": "Run the following command to find references to objects which use environment variables defined from secrets. ``` kubectl get all -o jsonpath='{range .items[?(@..secretKeyRef)]}{.kind}{@.metadata.name}{end}' -A ```", + "AdditionalInformation": "Mounting secrets as volumes has the additional benefit that secret values can be updated without restarting the pod", + "References": "https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets", + "DefaultValue": "By default, secrets are not defined" + } + ] + }, + { + "Id": "5.4.2", + "Description": "Consider external secret storage", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.4 Secrets Management", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Consider the use of an external secrets storage and management system, instead of using Kubernetes Secrets directly, if you have more complex secret management needs. Ensure the solution requires authentication to access secrets, has auditing of access to and use of secrets, and encrypts secrets. Some solutions also make it easier to rotate secrets.", + "RationaleStatement": "Kubernetes supports secrets as first-class objects, but care needs to be taken to ensure that access to secrets is carefully limited. Using an external secrets provider can ease the management of access to secrets, especially where secrests are used across both Kubernetes and non-Kubernetes environments.", + "ImpactStatement": "None", + "RemediationProcedure": "Refer to the secrets management options offered by your cloud provider or a third-party secrets management solution.", + "AuditProcedure": "Review your secrets management implementation.", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "By default, no external secret management is configured." + } + ] + }, + { + "Id": "5.5.1", + "Description": "Configure Image Provenance using ImagePolicyWebhook admission controller", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.5 Extensible Admission Control", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Configure Image Provenance for your deployment.", + "RationaleStatement": "Kubernetes supports plugging in provenance rules to accept or reject the images in your deployments. You could configure such rules to ensure that only approved images are deployed in the cluster.", + "ImpactStatement": "You need to regularly maintain your provenance configuration based on container image updates.", + "RemediationProcedure": "Follow the Kubernetes documentation and setup image provenance.", + "AuditProcedure": "Review the pod definitions in your cluster and verify that image provenance is configured as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/admin/admission-controllers/#imagepolicywebhook:https://github.com/kubernetes/community/blob/master/contributors/design-proposals/image-provenance.md:https://hub.docker.com/r/dnurmi/anchore-toolbox/:https://github.com/kubernetes/kubernetes/issues/22888", + "DefaultValue": "By default, image provenance is not set." + } + ] + }, + { + "Id": "5.6.1", + "Description": "Create administrative boundaries between resources using namespaces", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.6 General Policies", + "Profile": "Level 1 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Use namespaces to isolate your Kubernetes objects.", + "RationaleStatement": "Limiting the scope of user permissions can reduce the impact of mistakes or malicious activities. A Kubernetes namespace allows you to partition created resources into logically named groups. Resources created in one namespace can be hidden from other namespaces. By default, each resource created by a user in Kubernetes cluster runs in a default namespace, called `default`. You can create additional namespaces and attach resources and users to them. You can use Kubernetes Authorization plugins to create policies that segregate access to namespace resources between different users.", + "ImpactStatement": "You need to switch between namespaces for administration.", + "RemediationProcedure": "Follow the documentation and create namespaces for objects in your deployment as you need them.", + "AuditProcedure": "Run the below command and review the namespaces created in the cluster. ``` kubectl get namespaces ``` Ensure that these namespaces are the ones you need and are adequately administered as per your requirements.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#viewing-namespaces:http://blog.kubernetes.io/2016/08/security-best-practices-kubernetes-deployment.html:https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/589-efficient-node-heartbeats", + "DefaultValue": "By default, Kubernetes starts with 4 initial namespaces: 1. `default` - The default namespace for objects with no other namespace 1. `kube-system` - The namespace for objects created by the Kubernetes system 1. `kube-node-lease` - Namespace used for node heartbeats 1. `kube-public` - Namespace used for public information in a cluster" + } + ] + }, + { + "Id": "5.6.2", + "Description": "Ensure that the seccomp profile is set to docker/default in your pod definitions", + "Checks": [ + "core_seccomp_profile_docker_default" + ], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.6 General Policies", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Enable `docker/default` seccomp profile in your pod definitions.", + "RationaleStatement": "Seccomp (secure computing mode) is used to restrict the set of system calls applications can make, allowing cluster administrators greater control over the security of workloads running in the cluster. Kubernetes disables seccomp profiles by default for historical reasons. You should enable it to ensure that the workloads have restricted actions available within the container.", + "ImpactStatement": "If the `docker/default` seccomp profile is too restrictive for you, you would have to create/manage your own seccomp profiles.", + "RemediationProcedure": "Use security context to enable the `docker/default` seccomp profile in your pod definitions. An example is as below: ``` securityContext: seccompProfile: type: RuntimeDefault ```", + "AuditProcedure": "Review the pod definitions in your cluster. It should create a line as below: ``` securityContext: seccompProfile: type: RuntimeDefault ```", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/tutorials/clusters/seccomp/:https://docs.docker.com/engine/security/seccomp/", + "DefaultValue": "By default, seccomp profile is set to `unconfined` which means that no seccomp profiles are enabled." + } + ] + }, + { + "Id": "5.6.3", + "Description": "Apply Security Context to Your Pods and Containers", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.6 General Policies", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Apply Security Context to Your Pods and Containers", + "RationaleStatement": "A security context defines the operating system security settings (uid, gid, capabilities, SELinux role, etc..) applied to a container. When designing your containers and pods, make sure that you configure the security context for your pods, containers, and volumes. A security context is a property defined in the deployment yaml. It controls the security parameters that will be assigned to the pod/container/volume. There are two levels of security context: pod level security context, and container level security context.", + "ImpactStatement": "If you incorrectly apply security contexts, you may have trouble running the pods.", + "RemediationProcedure": "Follow the Kubernetes documentation and apply security contexts to your pods. For a suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker Containers.", + "AuditProcedure": "Review the pod definitions in your cluster and verify that you have security contexts defined as appropriate.", + "AdditionalInformation": "", + "References": "https://kubernetes.io/docs/concepts/policy/security-context/:https://learn.cisecurity.org/benchmarks", + "DefaultValue": "By default, no security contexts are automatically applied to pods." + } + ] + }, + { + "Id": "5.6.4", + "Description": "The default namespace should not be used", + "Checks": [], + "Attributes": [ + { + "Section": "5 Policies", + "SubSection": "5.6 General Policies", + "Profile": "Level 2 - Master Node", + "AssessmentStatus": "Manual", + "Description": "Kubernetes provides a default namespace, where objects are placed if no namespace is specified for them. Placing objects in this namespace makes application of RBAC and other controls more difficult.", + "RationaleStatement": "Resources in a Kubernetes cluster should be segregated by namespace, to allow for security controls to be applied at that level and to make it easier to manage resources.", + "ImpactStatement": "None", + "RemediationProcedure": "Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace.", + "AuditProcedure": "Run this command to list objects in default namespace ``` kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) --ignore-not-found -n default ``` The only entries there should be system managed resources such as the `kubernetes` service", + "AdditionalInformation": "", + "References": "", + "DefaultValue": "Unless a namespace is specific on object creation, the `default` namespace will be used" + } + ] + } + ] +} From 7016779b8ee87c98049362229ecb606d721072de Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 21 May 2025 11:31:23 +0200 Subject: [PATCH 357/359] chore(README): update `README.md` (#7799) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ccab5e285b..9064d36891 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

    - Prowler Open Source is as dynamic and adaptable as the environment it secures. It is trusted by the industry leaders to uphold the highest standards in security. + Prowler is the Open Cloud Security platform trusted by thousands to automate security and compliance in any cloud environment. With hundreds of ready-to-use checks and compliance frameworks, Prowler delivers real-time, customizable monitoring and seamless integrations, making cloud security simple, scalable, and cost-effective for organizations of any size.

    Learn more at prowler.com From 31ea672c613d013c018d8ab0decbe6c08f6e24ae Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Wed, 21 May 2025 11:45:54 +0200 Subject: [PATCH 358/359] fix: move changes to release 5.8 (#7801) --- prowler/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9c0f1cb886..bfe2c91df2 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -7,8 +7,12 @@ All notable changes to the **Prowler SDK** are documented in this file. ### Added - Add CIS 1.11 compliance framework for Kubernetes. [(#7790)](https://github.com/prowler-cloud/prowler/pull/7790) - Support `HTTPS_PROXY` and `K8S_SKIP_TLS_VERIFY` in Kubernetes. [(#7720)](https://github.com/prowler-cloud/prowler/pull/7720) +- Add new check `entra_users_mfa_capable`. [(#7734)](https://github.com/prowler-cloud/prowler/pull/7734) +- Add new check `admincenter_organization_customer_lockbox_enabled`. [(#7732)](https://github.com/prowler-cloud/prowler/pull/7732) +- Add new check `admincenter_external_calendar_sharing_disabled`. [(#7733)](https://github.com/prowler-cloud/prowler/pull/7733) ### Fixed +- Fix `m365_powershell test_credentials` to use sanitized credentials. [(#7761)](https://github.com/prowler-cloud/prowler/pull/7761) --- @@ -18,9 +22,6 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update the compliance list supported for each provider from docs. [(#7694)](https://github.com/prowler-cloud/prowler/pull/7694) - Allow setting cluster name in in-cluster mode in Kubernetes. [(#7695)](https://github.com/prowler-cloud/prowler/pull/7695) - Add Prowler ThreatScore for M365 provider. [(#7692)](https://github.com/prowler-cloud/prowler/pull/7692) -- Add new check `entra_users_mfa_capable`. [(#7734)](https://github.com/prowler-cloud/prowler/pull/7734) -- Add new check `admincenter_organization_customer_lockbox_enabled`. [(#7732)](https://github.com/prowler-cloud/prowler/pull/7732) -- Add new check `admincenter_external_calendar_sharing_disabled`. [(#7733)](https://github.com/prowler-cloud/prowler/pull/7733) - Add GitHub provider. [(#5787)](https://github.com/prowler-cloud/prowler/pull/5787) - Add `repository_default_branch_requires_multiple_approvals` check for GitHub provider. [(#6160)](https://github.com/prowler-cloud/prowler/pull/6160) - Add `repository_default_branch_protection_enabled` check for GitHub provider. [(#6161)](https://github.com/prowler-cloud/prowler/pull/6161) @@ -39,7 +40,6 @@ All notable changes to the **Prowler SDK** are documented in this file. - Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699) - Update and upgrade CIS for all the providers [(#7738)](https://github.com/prowler-cloud/prowler/pull/7738) - Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750) -- Fix `m365_powershell test_credentials` to use sanitized credentials. [(#7761)](https://github.com/prowler-cloud/prowler/pull/7761) - Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764) --- From 1c1c58c97585c3d1bf3a246f840d3a3ae48deeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Wed, 21 May 2025 11:56:54 +0200 Subject: [PATCH 359/359] feat(findings): Add new index for finding UID lookup (#7800) --- api/CHANGELOG.md | 7 +++++ api/pyproject.toml | 2 +- .../0024_findings_uid_index_partitions.py | 29 +++++++++++++++++++ .../0025_findings_uid_index_parent.py | 17 +++++++++++ api/src/backend/api/models.py | 4 +++ api/src/backend/api/specs/v1.yaml | 2 +- api/src/backend/api/v1/views.py | 2 +- 7 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 api/src/backend/api/migrations/0024_findings_uid_index_partitions.py create mode 100644 api/src/backend/api/migrations/0025_findings_uid_index_parent.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 96dc979d1e..2f0ba3cce0 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to the **Prowler API** are documented in this file. +## [v1.8.1] (Prowler v5.7.1) + +### Fixed +- Added database index to improve performance on finding lookup. [(#7800)](https://github.com/prowler-cloud/prowler/pull/7800) + +--- + ## [v1.8.0] (Prowler v5.7.0) ### Added diff --git a/api/pyproject.toml b/api/pyproject.toml index ce79dcbc7a..19190f8893 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -35,7 +35,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.8.0" +version = "1.8.1" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/api/migrations/0024_findings_uid_index_partitions.py b/api/src/backend/api/migrations/0024_findings_uid_index_partitions.py new file mode 100644 index 0000000000..d0e237453e --- /dev/null +++ b/api/src/backend/api/migrations/0024_findings_uid_index_partitions.py @@ -0,0 +1,29 @@ +from functools import partial + +from django.db import migrations + +from api.db_utils import create_index_on_partitions, drop_index_on_partitions + + +class Migration(migrations.Migration): + atomic = False + + dependencies = [ + ("api", "0023_resources_lookup_optimization"), + ] + + operations = [ + migrations.RunPython( + partial( + create_index_on_partitions, + parent_table="findings", + index_name="find_tenant_uid_inserted_idx", + columns="tenant_id, uid, inserted_at DESC", + ), + reverse_code=partial( + drop_index_on_partitions, + parent_table="findings", + index_name="find_tenant_uid_inserted_idx", + ), + ) + ] diff --git a/api/src/backend/api/migrations/0025_findings_uid_index_parent.py b/api/src/backend/api/migrations/0025_findings_uid_index_parent.py new file mode 100644 index 0000000000..fa64ae925b --- /dev/null +++ b/api/src/backend/api/migrations/0025_findings_uid_index_parent.py @@ -0,0 +1,17 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0024_findings_uid_index_partitions"), + ] + + operations = [ + migrations.AddIndex( + model_name="finding", + index=models.Index( + fields=["tenant_id", "uid", "-inserted_at"], + name="find_tenant_uid_inserted_idx", + ), + ), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 3b85d2208f..a427bcf9c9 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -755,6 +755,10 @@ class Finding(PostgresPartitionedModel, RowLevelSecurityProtectedModel): condition=Q(delta="new"), name="find_delta_new_idx", ), + models.Index( + fields=["tenant_id", "uid", "-inserted_at"], + name="find_tenant_uid_inserted_idx", + ), GinIndex(fields=["resource_services"], name="gin_find_service_idx"), GinIndex(fields=["resource_regions"], name="gin_find_region_idx"), GinIndex(fields=["resource_types"], name="gin_find_rtype_idx"), diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 4a5bdb4662..3f90c28cb1 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.8.0 + version: 1.8.1 description: |- Prowler API specification. diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 04810f28df..b3e39fef50 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -260,7 +260,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.8.0" + spectacular_settings.VERSION = "1.8.1" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." )